bin-dec-conversions 0.1.1__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.
Potentially problematic release.
This version of bin-dec-conversions might be problematic. Click here for more details.
- bin_dec_conversions-0.1.1/LICENSE +21 -0
- bin_dec_conversions-0.1.1/PKG-INFO +144 -0
- bin_dec_conversions-0.1.1/README.md +130 -0
- bin_dec_conversions-0.1.1/pyproject.toml +34 -0
- bin_dec_conversions-0.1.1/setup.cfg +4 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions/__init__.py +3 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions/bin_dec_conversions.py +32 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions/cli.py +107 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/PKG-INFO +144 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/SOURCES.txt +14 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/dependency_links.txt +1 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/entry_points.txt +2 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/requires.txt +1 -0
- bin_dec_conversions-0.1.1/src/bin_dec_conversions.egg-info/top_level.txt +1 -0
- bin_dec_conversions-0.1.1/tests/test_bin_dec_conversion.py +85 -0
- bin_dec_conversions-0.1.1/tests/test_cli.py +33 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marco S. Tornabene
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bin-dec-conversions
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Convert between binary and decimal from Python or the command line
|
|
5
|
+
Author-email: Marco Salvatore Tornabene <tornabenemarco56@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/JustM4rk123/bin_dec_conversions
|
|
8
|
+
Keywords: binary,decimal,conversion
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: questionary
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# bin-dec-conversions
|
|
16
|
+
|
|
17
|
+
Convert binary numbers to decimal and decimal integers to binary with a small
|
|
18
|
+
Python library and command-line interface.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- Convert a non-empty string of `0`s and `1`s to a decimal integer.
|
|
23
|
+
- Convert a non-negative integer to binary, optionally padding the output to a
|
|
24
|
+
minimum width.
|
|
25
|
+
- Use the interactive menu or run a conversion directly with command-line
|
|
26
|
+
options.
|
|
27
|
+
- Validate inputs and report invalid values.
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Python 3.10 or newer.
|
|
32
|
+
- [`questionary`](https://github.com/tmbo/questionary) is installed automatically
|
|
33
|
+
and is used by the interactive menu.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Clone the repository and install the package:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/JustM4rk123/bin_dec_conversions.git
|
|
41
|
+
cd bin_dec_conversions
|
|
42
|
+
python -m pip install .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Command line
|
|
48
|
+
|
|
49
|
+
Run without arguments to open the interactive menu. Select a conversion with
|
|
50
|
+
the arrow keys and Enter, then enter a value:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Which operation do you want to perform? From binary to decimal
|
|
54
|
+
Insert a binary number: 1010
|
|
55
|
+
The decimal equivalent of 1010 is 10
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
In interactive mode, invalid input displays an error and prompts again. You can
|
|
59
|
+
also convert directly with flags:
|
|
60
|
+
|
|
61
|
+
```console
|
|
62
|
+
$ bin-dec-conversions --to-decimal 1010
|
|
63
|
+
10
|
|
64
|
+
|
|
65
|
+
$ bin-dec-conversions --to-binary 10
|
|
66
|
+
1010
|
|
67
|
+
|
|
68
|
+
$ bin-dec-conversions --to-binary 10 --width 8
|
|
69
|
+
00001010
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use `-d` for `--to-decimal`, `-b` for `--to-binary`, and `-w` for `--width`.
|
|
73
|
+
The conversion options are mutually exclusive. The width option zero-pads
|
|
74
|
+
binary output to at least the requested number of characters; it never
|
|
75
|
+
truncates a result. Invalid flag-mode input is reported as an error and exits
|
|
76
|
+
with a non-zero status.
|
|
77
|
+
|
|
78
|
+
### Python library
|
|
79
|
+
|
|
80
|
+
The public API provides two functions:
|
|
81
|
+
|
|
82
|
+
- `binary_to_decimal(binary: str) -> int` converts a non-empty string containing
|
|
83
|
+
only `0`s and `1`s. It raises `ValueError` for empty strings or other
|
|
84
|
+
characters.
|
|
85
|
+
- `decimal_to_binary(decimal: int, width: int = 0) -> str` converts a
|
|
86
|
+
non-negative integer to binary, left-padded with zeros to at least `width`
|
|
87
|
+
characters. It raises `ValueError` if the value or width is negative.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from bin_dec_conversions import binary_to_decimal, decimal_to_binary
|
|
91
|
+
|
|
92
|
+
binary_to_decimal("1010") # 10
|
|
93
|
+
binary_to_decimal("0001") # 1 (leading zeros are allowed)
|
|
94
|
+
|
|
95
|
+
decimal_to_binary(10) # "1010"
|
|
96
|
+
decimal_to_binary(5, width=8) # "00000101"
|
|
97
|
+
decimal_to_binary(255, width=4) # "11111111" (never truncated)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
Create a virtual environment and install the project in editable mode with its
|
|
103
|
+
development dependencies:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python -m venv .venv
|
|
107
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
108
|
+
python -m pip install -e . --group dev # requires pip 25.1+
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Alternatively, with [uv](https://docs.astral.sh/uv/), run `uv sync`. The `dev`
|
|
112
|
+
dependency group includes `pytest`, `black`, and `ruff`.
|
|
113
|
+
|
|
114
|
+
Run the tests:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
python -m pytest
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Format and lint:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
black .
|
|
124
|
+
ruff check .
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Project structure
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
bin_dec_conversions/
|
|
131
|
+
├── pyproject.toml
|
|
132
|
+
├── src/
|
|
133
|
+
│ └── bin_dec_conversions/
|
|
134
|
+
│ ├── __init__.py # public API
|
|
135
|
+
│ ├── bin_dec_conversions.py # conversion functions
|
|
136
|
+
│ └── cli.py # command-line interface
|
|
137
|
+
└── tests/
|
|
138
|
+
├── test_bin_dec_conversion.py
|
|
139
|
+
└── test_cli.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# bin-dec-conversions
|
|
2
|
+
|
|
3
|
+
Convert binary numbers to decimal and decimal integers to binary with a small
|
|
4
|
+
Python library and command-line interface.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- Convert a non-empty string of `0`s and `1`s to a decimal integer.
|
|
9
|
+
- Convert a non-negative integer to binary, optionally padding the output to a
|
|
10
|
+
minimum width.
|
|
11
|
+
- Use the interactive menu or run a conversion directly with command-line
|
|
12
|
+
options.
|
|
13
|
+
- Validate inputs and report invalid values.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Python 3.10 or newer.
|
|
18
|
+
- [`questionary`](https://github.com/tmbo/questionary) is installed automatically
|
|
19
|
+
and is used by the interactive menu.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Clone the repository and install the package:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/JustM4rk123/bin_dec_conversions.git
|
|
27
|
+
cd bin_dec_conversions
|
|
28
|
+
python -m pip install .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Command line
|
|
34
|
+
|
|
35
|
+
Run without arguments to open the interactive menu. Select a conversion with
|
|
36
|
+
the arrow keys and Enter, then enter a value:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
Which operation do you want to perform? From binary to decimal
|
|
40
|
+
Insert a binary number: 1010
|
|
41
|
+
The decimal equivalent of 1010 is 10
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
In interactive mode, invalid input displays an error and prompts again. You can
|
|
45
|
+
also convert directly with flags:
|
|
46
|
+
|
|
47
|
+
```console
|
|
48
|
+
$ bin-dec-conversions --to-decimal 1010
|
|
49
|
+
10
|
|
50
|
+
|
|
51
|
+
$ bin-dec-conversions --to-binary 10
|
|
52
|
+
1010
|
|
53
|
+
|
|
54
|
+
$ bin-dec-conversions --to-binary 10 --width 8
|
|
55
|
+
00001010
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use `-d` for `--to-decimal`, `-b` for `--to-binary`, and `-w` for `--width`.
|
|
59
|
+
The conversion options are mutually exclusive. The width option zero-pads
|
|
60
|
+
binary output to at least the requested number of characters; it never
|
|
61
|
+
truncates a result. Invalid flag-mode input is reported as an error and exits
|
|
62
|
+
with a non-zero status.
|
|
63
|
+
|
|
64
|
+
### Python library
|
|
65
|
+
|
|
66
|
+
The public API provides two functions:
|
|
67
|
+
|
|
68
|
+
- `binary_to_decimal(binary: str) -> int` converts a non-empty string containing
|
|
69
|
+
only `0`s and `1`s. It raises `ValueError` for empty strings or other
|
|
70
|
+
characters.
|
|
71
|
+
- `decimal_to_binary(decimal: int, width: int = 0) -> str` converts a
|
|
72
|
+
non-negative integer to binary, left-padded with zeros to at least `width`
|
|
73
|
+
characters. It raises `ValueError` if the value or width is negative.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from bin_dec_conversions import binary_to_decimal, decimal_to_binary
|
|
77
|
+
|
|
78
|
+
binary_to_decimal("1010") # 10
|
|
79
|
+
binary_to_decimal("0001") # 1 (leading zeros are allowed)
|
|
80
|
+
|
|
81
|
+
decimal_to_binary(10) # "1010"
|
|
82
|
+
decimal_to_binary(5, width=8) # "00000101"
|
|
83
|
+
decimal_to_binary(255, width=4) # "11111111" (never truncated)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
Create a virtual environment and install the project in editable mode with its
|
|
89
|
+
development dependencies:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
python -m venv .venv
|
|
93
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
94
|
+
python -m pip install -e . --group dev # requires pip 25.1+
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Alternatively, with [uv](https://docs.astral.sh/uv/), run `uv sync`. The `dev`
|
|
98
|
+
dependency group includes `pytest`, `black`, and `ruff`.
|
|
99
|
+
|
|
100
|
+
Run the tests:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python -m pytest
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Format and lint:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
black .
|
|
110
|
+
ruff check .
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Project structure
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
bin_dec_conversions/
|
|
117
|
+
├── pyproject.toml
|
|
118
|
+
├── src/
|
|
119
|
+
│ └── bin_dec_conversions/
|
|
120
|
+
│ ├── __init__.py # public API
|
|
121
|
+
│ ├── bin_dec_conversions.py # conversion functions
|
|
122
|
+
│ └── cli.py # command-line interface
|
|
123
|
+
└── tests/
|
|
124
|
+
├── test_bin_dec_conversion.py
|
|
125
|
+
└── test_cli.py
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "bin-dec-conversions"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
authors = [{name = "Marco Salvatore Tornabene", email = "tornabenemarco56@gmail.com"}]
|
|
10
|
+
description = "Convert between binary and decimal from Python or the command line"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
keywords = ["binary", "decimal", "conversion"]
|
|
15
|
+
dependencies = ["questionary"]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Repository = "https://github.com/JustM4rk123/bin_dec_conversions"
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
"pytest>=8",
|
|
23
|
+
"black",
|
|
24
|
+
"ruff",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src"]
|
|
29
|
+
|
|
30
|
+
[tool.pytest.ini_options]
|
|
31
|
+
testpaths = ["tests"]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
bin-dec-conversions = "bin_dec_conversions.cli:main"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def binary_to_decimal(binary: str) -> int:
|
|
5
|
+
if not re.fullmatch(r"[01]+", binary):
|
|
6
|
+
raise ValueError("Binary must contain only 0s and 1s")
|
|
7
|
+
|
|
8
|
+
decimal = 0
|
|
9
|
+
for i, bit in enumerate(reversed(binary)):
|
|
10
|
+
if bit == "1":
|
|
11
|
+
decimal += 2**i
|
|
12
|
+
|
|
13
|
+
return decimal
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def decimal_to_binary(decimal: int, width: int = 0) -> str:
|
|
17
|
+
"""Convert a non-negative integer to binary, left-padded with zeros to `width`."""
|
|
18
|
+
if decimal < 0:
|
|
19
|
+
raise ValueError("Decimal must be non-negative")
|
|
20
|
+
if width < 0:
|
|
21
|
+
raise ValueError("Width must be non-negative")
|
|
22
|
+
|
|
23
|
+
if decimal == 0:
|
|
24
|
+
bits = "0"
|
|
25
|
+
else:
|
|
26
|
+
digits = []
|
|
27
|
+
while decimal > 0:
|
|
28
|
+
digits.append(str(decimal % 2))
|
|
29
|
+
decimal //= 2
|
|
30
|
+
bits = "".join(reversed(digits))
|
|
31
|
+
|
|
32
|
+
return bits.zfill(width)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import questionary
|
|
5
|
+
|
|
6
|
+
from bin_dec_conversions import binary_to_decimal, decimal_to_binary
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def prompt_binary_to_decimal() -> None:
|
|
10
|
+
while True:
|
|
11
|
+
binary = input("Insert a binary number: ").strip()
|
|
12
|
+
try:
|
|
13
|
+
decimal = binary_to_decimal(binary)
|
|
14
|
+
except ValueError as e:
|
|
15
|
+
print(e)
|
|
16
|
+
else:
|
|
17
|
+
print(f"The decimal equivalent of {binary} is {decimal}")
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def prompt_decimal_to_binary() -> None:
|
|
22
|
+
while True:
|
|
23
|
+
raw = input("Insert a decimal number: ").strip()
|
|
24
|
+
try:
|
|
25
|
+
decimal = int(raw)
|
|
26
|
+
except ValueError:
|
|
27
|
+
print("Insert a whole number!")
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
binary = decimal_to_binary(decimal)
|
|
32
|
+
except ValueError as e:
|
|
33
|
+
print(e)
|
|
34
|
+
else:
|
|
35
|
+
print(f"The binary equivalent of {decimal} is {binary}")
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def interactive_menu():
|
|
40
|
+
choice = questionary.select(
|
|
41
|
+
"Which operation do you want to perform?",
|
|
42
|
+
choices=[
|
|
43
|
+
"From binary to decimal",
|
|
44
|
+
"From decimal to binary",
|
|
45
|
+
],
|
|
46
|
+
).ask()
|
|
47
|
+
|
|
48
|
+
match choice:
|
|
49
|
+
case "From binary to decimal":
|
|
50
|
+
prompt_binary_to_decimal()
|
|
51
|
+
case "From decimal to binary":
|
|
52
|
+
prompt_decimal_to_binary()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def create_parser():
|
|
56
|
+
parser = argparse.ArgumentParser(
|
|
57
|
+
prog="bin-dec-conversions",
|
|
58
|
+
description="Convert between binary and decimal. "
|
|
59
|
+
"Run with no arguments for interactive mode.",
|
|
60
|
+
)
|
|
61
|
+
group = parser.add_mutually_exclusive_group()
|
|
62
|
+
group.add_argument(
|
|
63
|
+
"-d",
|
|
64
|
+
"--to-decimal",
|
|
65
|
+
metavar="BINARY",
|
|
66
|
+
help="convert a binary string to decimal",
|
|
67
|
+
)
|
|
68
|
+
group.add_argument(
|
|
69
|
+
"-b",
|
|
70
|
+
"--to-binary",
|
|
71
|
+
metavar="DECIMAL",
|
|
72
|
+
type=int,
|
|
73
|
+
help="convert a non-negative integer to binary",
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"-w",
|
|
77
|
+
"--width",
|
|
78
|
+
type=int,
|
|
79
|
+
default=0,
|
|
80
|
+
help="zero-pad the binary output to this width (only with --to-binary)",
|
|
81
|
+
)
|
|
82
|
+
return parser
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main(argv: list[str] | None = None) -> int:
|
|
86
|
+
parser = create_parser()
|
|
87
|
+
args = parser.parse_args(argv)
|
|
88
|
+
|
|
89
|
+
if args.width and args.to_binary is None:
|
|
90
|
+
parser.error("--width can only be used with --to-binary")
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
if args.to_decimal is not None:
|
|
94
|
+
print(binary_to_decimal(args.to_decimal))
|
|
95
|
+
elif args.to_binary is not None:
|
|
96
|
+
print(decimal_to_binary(args.to_binary, args.width))
|
|
97
|
+
else:
|
|
98
|
+
interactive_menu()
|
|
99
|
+
except ValueError as e:
|
|
100
|
+
print(e, file=sys.stderr)
|
|
101
|
+
return 1
|
|
102
|
+
|
|
103
|
+
return 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == "__main__":
|
|
107
|
+
raise SystemError(main())
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bin-dec-conversions
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Convert between binary and decimal from Python or the command line
|
|
5
|
+
Author-email: Marco Salvatore Tornabene <tornabenemarco56@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/JustM4rk123/bin_dec_conversions
|
|
8
|
+
Keywords: binary,decimal,conversion
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: questionary
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# bin-dec-conversions
|
|
16
|
+
|
|
17
|
+
Convert binary numbers to decimal and decimal integers to binary with a small
|
|
18
|
+
Python library and command-line interface.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- Convert a non-empty string of `0`s and `1`s to a decimal integer.
|
|
23
|
+
- Convert a non-negative integer to binary, optionally padding the output to a
|
|
24
|
+
minimum width.
|
|
25
|
+
- Use the interactive menu or run a conversion directly with command-line
|
|
26
|
+
options.
|
|
27
|
+
- Validate inputs and report invalid values.
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Python 3.10 or newer.
|
|
32
|
+
- [`questionary`](https://github.com/tmbo/questionary) is installed automatically
|
|
33
|
+
and is used by the interactive menu.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Clone the repository and install the package:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/JustM4rk123/bin_dec_conversions.git
|
|
41
|
+
cd bin_dec_conversions
|
|
42
|
+
python -m pip install .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Command line
|
|
48
|
+
|
|
49
|
+
Run without arguments to open the interactive menu. Select a conversion with
|
|
50
|
+
the arrow keys and Enter, then enter a value:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Which operation do you want to perform? From binary to decimal
|
|
54
|
+
Insert a binary number: 1010
|
|
55
|
+
The decimal equivalent of 1010 is 10
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
In interactive mode, invalid input displays an error and prompts again. You can
|
|
59
|
+
also convert directly with flags:
|
|
60
|
+
|
|
61
|
+
```console
|
|
62
|
+
$ bin-dec-conversions --to-decimal 1010
|
|
63
|
+
10
|
|
64
|
+
|
|
65
|
+
$ bin-dec-conversions --to-binary 10
|
|
66
|
+
1010
|
|
67
|
+
|
|
68
|
+
$ bin-dec-conversions --to-binary 10 --width 8
|
|
69
|
+
00001010
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use `-d` for `--to-decimal`, `-b` for `--to-binary`, and `-w` for `--width`.
|
|
73
|
+
The conversion options are mutually exclusive. The width option zero-pads
|
|
74
|
+
binary output to at least the requested number of characters; it never
|
|
75
|
+
truncates a result. Invalid flag-mode input is reported as an error and exits
|
|
76
|
+
with a non-zero status.
|
|
77
|
+
|
|
78
|
+
### Python library
|
|
79
|
+
|
|
80
|
+
The public API provides two functions:
|
|
81
|
+
|
|
82
|
+
- `binary_to_decimal(binary: str) -> int` converts a non-empty string containing
|
|
83
|
+
only `0`s and `1`s. It raises `ValueError` for empty strings or other
|
|
84
|
+
characters.
|
|
85
|
+
- `decimal_to_binary(decimal: int, width: int = 0) -> str` converts a
|
|
86
|
+
non-negative integer to binary, left-padded with zeros to at least `width`
|
|
87
|
+
characters. It raises `ValueError` if the value or width is negative.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from bin_dec_conversions import binary_to_decimal, decimal_to_binary
|
|
91
|
+
|
|
92
|
+
binary_to_decimal("1010") # 10
|
|
93
|
+
binary_to_decimal("0001") # 1 (leading zeros are allowed)
|
|
94
|
+
|
|
95
|
+
decimal_to_binary(10) # "1010"
|
|
96
|
+
decimal_to_binary(5, width=8) # "00000101"
|
|
97
|
+
decimal_to_binary(255, width=4) # "11111111" (never truncated)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
Create a virtual environment and install the project in editable mode with its
|
|
103
|
+
development dependencies:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python -m venv .venv
|
|
107
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
108
|
+
python -m pip install -e . --group dev # requires pip 25.1+
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Alternatively, with [uv](https://docs.astral.sh/uv/), run `uv sync`. The `dev`
|
|
112
|
+
dependency group includes `pytest`, `black`, and `ruff`.
|
|
113
|
+
|
|
114
|
+
Run the tests:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
python -m pytest
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Format and lint:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
black .
|
|
124
|
+
ruff check .
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Project structure
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
bin_dec_conversions/
|
|
131
|
+
├── pyproject.toml
|
|
132
|
+
├── src/
|
|
133
|
+
│ └── bin_dec_conversions/
|
|
134
|
+
│ ├── __init__.py # public API
|
|
135
|
+
│ ├── bin_dec_conversions.py # conversion functions
|
|
136
|
+
│ └── cli.py # command-line interface
|
|
137
|
+
└── tests/
|
|
138
|
+
├── test_bin_dec_conversion.py
|
|
139
|
+
└── test_cli.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/bin_dec_conversions/__init__.py
|
|
5
|
+
src/bin_dec_conversions/bin_dec_conversions.py
|
|
6
|
+
src/bin_dec_conversions/cli.py
|
|
7
|
+
src/bin_dec_conversions.egg-info/PKG-INFO
|
|
8
|
+
src/bin_dec_conversions.egg-info/SOURCES.txt
|
|
9
|
+
src/bin_dec_conversions.egg-info/dependency_links.txt
|
|
10
|
+
src/bin_dec_conversions.egg-info/entry_points.txt
|
|
11
|
+
src/bin_dec_conversions.egg-info/requires.txt
|
|
12
|
+
src/bin_dec_conversions.egg-info/top_level.txt
|
|
13
|
+
tests/test_bin_dec_conversion.py
|
|
14
|
+
tests/test_cli.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
questionary
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bin_dec_conversions
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from bin_dec_conversions import binary_to_decimal, decimal_to_binary
|
|
4
|
+
|
|
5
|
+
# --- binary_to_decimal ---
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.parametrize(
|
|
9
|
+
"binary, expected",
|
|
10
|
+
[
|
|
11
|
+
("0", 0),
|
|
12
|
+
("1", 1),
|
|
13
|
+
("1010", 10),
|
|
14
|
+
("10000000", 128),
|
|
15
|
+
("11111111", 255),
|
|
16
|
+
("0001", 1), # leading zeros
|
|
17
|
+
],
|
|
18
|
+
)
|
|
19
|
+
def test_bin2dec(binary, expected):
|
|
20
|
+
assert binary_to_decimal(binary) == expected
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.parametrize("bad", ["", "20", "Cat", "1 0", "-101", "10.1", " 101"])
|
|
24
|
+
def test_bin2dec_invalid(bad):
|
|
25
|
+
with pytest.raises(ValueError):
|
|
26
|
+
binary_to_decimal(bad)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --- decimal_to_binary ---
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.parametrize(
|
|
33
|
+
"decimal, expected",
|
|
34
|
+
[
|
|
35
|
+
(0, "0"),
|
|
36
|
+
(1, "1"),
|
|
37
|
+
(10, "1010"),
|
|
38
|
+
(128, "10000000"),
|
|
39
|
+
(255, "11111111"),
|
|
40
|
+
],
|
|
41
|
+
)
|
|
42
|
+
def test_dec2bin(decimal, expected):
|
|
43
|
+
assert decimal_to_binary(decimal) == expected
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_dec2bin_negative():
|
|
47
|
+
with pytest.raises(ValueError):
|
|
48
|
+
decimal_to_binary(-10)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# --- width / padding (needed for 8-bit octets) ---
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.mark.parametrize(
|
|
55
|
+
"decimal, width, expected",
|
|
56
|
+
[
|
|
57
|
+
(5, 8, "00000101"),
|
|
58
|
+
(0, 8, "00000000"),
|
|
59
|
+
(255, 8, "11111111"),
|
|
60
|
+
(1, 4, "0001"),
|
|
61
|
+
(5, 0, "101"), # default: no padding
|
|
62
|
+
(255, 4, "11111111"), # width smaller than needed: never truncates
|
|
63
|
+
],
|
|
64
|
+
)
|
|
65
|
+
def test_dec2bin_width(decimal, width, expected):
|
|
66
|
+
assert decimal_to_binary(decimal, width) == expected
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_dec2bin_negative_width():
|
|
70
|
+
with pytest.raises(ValueError):
|
|
71
|
+
decimal_to_binary(5, -1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# --- cross-checks ---
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.mark.parametrize("n", range(300))
|
|
78
|
+
def test_matches_builtins(n):
|
|
79
|
+
assert decimal_to_binary(n) == bin(n)[2:]
|
|
80
|
+
assert binary_to_decimal(bin(n)[2:]) == n
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.mark.parametrize("n", [0, 1, 2, 10, 128, 255, 1023])
|
|
84
|
+
def test_round_trip(n):
|
|
85
|
+
assert binary_to_decimal(decimal_to_binary(n)) == n
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from bin_dec_conversions.cli import main
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_to_decimal(capsys):
|
|
7
|
+
assert main(["--to-decimal", "1010"]) == 0
|
|
8
|
+
assert capsys.readouterr().out.strip() == "10"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_to_binary_with_width(capsys):
|
|
12
|
+
assert main(["-b", "5", "-w", "8"]) == 0
|
|
13
|
+
assert capsys.readouterr().out.strip() == "00000101"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_invalid_binary(capsys):
|
|
17
|
+
assert main(["-d", "102"]) == 1
|
|
18
|
+
assert capsys.readouterr().err != ""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_negative_decimal(capsys):
|
|
22
|
+
assert main(["-b", "-5"]) == 1
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_width_without_to_binary():
|
|
26
|
+
with pytest.raises(SystemExit) as exc:
|
|
27
|
+
main(["--width", "8"])
|
|
28
|
+
assert exc.value.code == 2
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_mutually_exclusive():
|
|
32
|
+
with pytest.raises(SystemExit):
|
|
33
|
+
main(["-d", "101", "-b", "5"])
|