baseconvert 2.0.4__tar.gz → 2.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.
Files changed (36) hide show
  1. baseconvert-2.1.1/PKG-INFO +110 -0
  2. baseconvert-2.1.1/README.md +75 -0
  3. baseconvert-2.1.1/README.rst +90 -0
  4. baseconvert-2.1.1/VERSION.txt +1 -0
  5. baseconvert-2.1.1/baseconvert/ButtonRow.qml +80 -0
  6. baseconvert-2.1.1/baseconvert/__init__.py +13 -0
  7. baseconvert-2.1.1/baseconvert/__main__.py +90 -0
  8. baseconvert-2.1.1/baseconvert/app.qml +470 -0
  9. baseconvert-2.1.1/baseconvert/baseconvert.py +442 -0
  10. baseconvert-2.1.1/baseconvert/gui.py +86 -0
  11. baseconvert-2.1.1/baseconvert.egg-info/PKG-INFO +110 -0
  12. {baseconvert-2.0.4 → baseconvert-2.1.1}/baseconvert.egg-info/SOURCES.txt +6 -2
  13. baseconvert-2.1.1/pyproject.toml +40 -0
  14. baseconvert-2.1.1/tests/test_baseconvert.py +188 -0
  15. baseconvert-2.1.1/tests/test_cli.py +60 -0
  16. baseconvert-2.1.1/tests/test_coverage_paths.py +173 -0
  17. baseconvert-2.1.1/tests/test_entry_points.py +13 -0
  18. baseconvert-2.0.4/PKG-INFO +0 -179
  19. baseconvert-2.0.4/README.md +0 -159
  20. baseconvert-2.0.4/README.rst +0 -160
  21. baseconvert-2.0.4/VERSION.txt +0 -1
  22. baseconvert-2.0.4/baseconvert/ButtonRow.qml +0 -109
  23. baseconvert-2.0.4/baseconvert/__init__.py +0 -6
  24. baseconvert-2.0.4/baseconvert/__main__.py +0 -89
  25. baseconvert-2.0.4/baseconvert/app.qml +0 -270
  26. baseconvert-2.0.4/baseconvert/baseconvert.py +0 -831
  27. baseconvert-2.0.4/baseconvert/gui.py +0 -51
  28. baseconvert-2.0.4/baseconvert.egg-info/PKG-INFO +0 -179
  29. baseconvert-2.0.4/setup.py +0 -47
  30. {baseconvert-2.0.4 → baseconvert-2.1.1}/LICENSE.txt +0 -0
  31. {baseconvert-2.0.4 → baseconvert-2.1.1}/MANIFEST.in +0 -0
  32. {baseconvert-2.0.4 → baseconvert-2.1.1}/baseconvert.egg-info/dependency_links.txt +0 -0
  33. {baseconvert-2.0.4 → baseconvert-2.1.1}/baseconvert.egg-info/entry_points.txt +0 -0
  34. {baseconvert-2.0.4 → baseconvert-2.1.1}/baseconvert.egg-info/requires.txt +0 -0
  35. {baseconvert-2.0.4 → baseconvert-2.1.1}/baseconvert.egg-info/top_level.txt +0 -0
  36. {baseconvert-2.0.4 → baseconvert-2.1.1}/setup.cfg +0 -0
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: baseconvert
3
+ Version: 2.1.1
4
+ Summary: Convert numbers between bases.
5
+ Author: squdle, BreadMakesYouFull
6
+ License-Expression: MIT
7
+ Keywords: base,bases,radix,numeral system,number,hex,dec,bin,hexidecimal,binary,decimal,fraction,fractions,integer,convert,gui
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Topic :: Education
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Classifier: Intended Audience :: Education
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/x-rst
16
+ License-File: LICENSE.txt
17
+ Provides-Extra: gui
18
+ Requires-Dist: pyside6; extra == "gui"
19
+ Dynamic: license-file
20
+
21
+ baseconvert
22
+ ===========
23
+
24
+ Convert rational numbers between positive integer bases, with exact
25
+ arithmetic and recurring fractional digits.
26
+
27
+ Requires Python 3.10 or newer.
28
+
29
+ Install
30
+ -------
31
+
32
+ Install the library from PyPI::
33
+
34
+ python -m pip install baseconvert
35
+
36
+ For the GUI, install the optional dependencies and launch the application::
37
+
38
+ python -m pip install 'baseconvert[gui]'
39
+ baseconvert
40
+
41
+ Run from a source checkout
42
+ --------------------------
43
+
44
+ Install `just <https://just.systems/>`_, clone the repository, and run
45
+ ``just launch``. The recipe creates ``.venv`` and installs the GUI extra if
46
+ the launcher or PySide6 QML module is missing, then starts the GUI::
47
+
48
+ git clone https://github.com/BreadMakesYouFull/baseconvert.git
49
+ cd baseconvert
50
+ just launch
51
+
52
+ Development recipes
53
+ -------------------
54
+
55
+ Run these recipes from the repository root::
56
+
57
+ just install # editable install in .venv
58
+ just install-gui # editable install with GUI dependencies
59
+ just install-dev # install build, Black, and Twine
60
+ just format # format Python source
61
+ just lint # check formatting
62
+ just test # run doctests
63
+ just check # lint, doctests, then check files already in dist/
64
+ just build # clean, install development tools, build sdist and wheel
65
+ just clean # remove build artifacts AND .venv
66
+
67
+ ``just build`` first runs ``just clean``, which also deletes ``.venv``, and
68
+ then installs the build tools again. ``just check`` does not build
69
+ distributions; it runs ``twine check dist/*`` against files already in
70
+ ``dist/``. ``just publish-test`` and ``just publish`` run ``just check`` and
71
+ upload the existing ``dist/*`` files to TestPyPI or PyPI, respectively. To
72
+ build and validate distributions before publishing, run ``just build``
73
+ followed by ``just check`` and review the files in ``dist/``.
74
+
75
+ Python library
76
+ --------------
77
+
78
+ The API accepts strings, digit tuples, integers, floats, and
79
+ ``fractions.Fraction`` values. Use strings or ``Fraction`` to express exact
80
+ decimal values without float representation concerns::
81
+
82
+ from baseconvert import base
83
+
84
+ base("FF0.8", 16, 10, string=True) # '4080.5'
85
+ base("4080.5", 10, 16, string=True) # 'FF0.8'
86
+ base("-0.1", 3, 10, string=True, exact=True) # '-0.[3]'
87
+
88
+ The command-line interface reads a number argument or standard input. Bases
89
+ are integers; ``-s`` prints a string, and ``--no-recurring`` disables
90
+ recurring notation::
91
+
92
+ python -m baseconvert -n 4080.5 -i 10 -o 16 -s
93
+ echo 0.1 | python -m baseconvert -i 3 -o 10 --no-recurring -s
94
+
95
+ Digits, recurring fractions, and precision
96
+ ------------------------------------------
97
+
98
+ String digits are
99
+ ``0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz``. Values
100
+ above 61 use ascending Unicode characters; tuple representation is
101
+ recommended for bases above 61. In a digit tuple, each digit is a base-10
102
+ integer and the radix point is ``'.'``. A leading ``'-'`` represents a
103
+ negative value.
104
+
105
+ Recurring digits are enclosed in square brackets, for example ``0.[3]``.
106
+ ``max_depth`` limits fractional digits (default 10). Set ``exact=True`` or
107
+ ``max_depth=0`` to calculate the complete terminating or repeating expansion
108
+ when recurring output is enabled. Exact recurring detection uses rational
109
+ remainders. With recurring output disabled, an unlimited expansion is bounded
110
+ by ``MAX_DEPTH``.
@@ -0,0 +1,75 @@
1
+ # baseconvert
2
+
3
+ Convert rational numbers between positive integer bases, with exact arithmetic and recurring fractional digits.
4
+
5
+ ![baseconvert preview](./preview.gif)
6
+
7
+ [PyPI](https://pypi.org/project/baseconvert/) · [Flathub](https://flathub.org/apps/io.github.breadmakesyoufull.baseconvert) · [Windows release](https://github.com/BreadMakesYouFull/baseconvert/releases/tag/windows)
8
+
9
+ ## Install
10
+
11
+ Requires Python 3.10 or newer. Install the library from PyPI:
12
+
13
+ ```sh
14
+ python -m pip install baseconvert
15
+ ```
16
+
17
+ For the GUI, install the optional dependencies:
18
+
19
+ ```sh
20
+ python -m pip install 'baseconvert[gui]'
21
+ baseconvert
22
+ ```
23
+
24
+ ## Run from a source checkout
25
+
26
+ Install [`just`](https://just.systems/), clone the repository, and run `just launch`. The recipe creates `.venv` and installs the GUI extra if the launcher or PySide6 QML module is missing, then starts the GUI:
27
+
28
+ ```sh
29
+ git clone https://github.com/BreadMakesYouFull/baseconvert.git
30
+ cd baseconvert
31
+ just launch
32
+ ```
33
+
34
+ ## Development recipes
35
+
36
+ Run these from the repository root:
37
+
38
+ ```sh
39
+ just install # editable install in .venv
40
+ just install-gui # editable install with GUI dependencies
41
+ just install-dev # install build, Black, and Twine
42
+ just format # format Python source
43
+ just lint # check formatting
44
+ just test # run doctests
45
+ just check # lint, doctests, then check files already in dist/
46
+ just build # clean, install development tools, build sdist and wheel
47
+ just clean # remove build artifacts AND .venv
48
+ ```
49
+
50
+ `just build` first runs `just clean`, which also deletes `.venv`, and then installs the build tools again. `just check` does not build distributions; it runs `twine check dist/*` against whatever is currently in `dist/`. `just publish-test` and `just publish` run `just check` and upload the existing `dist/*` files to TestPyPI or PyPI, respectively. To build and validate distributions before publishing, run `just build` followed by `just check` and review the files in `dist/`.
51
+
52
+ ## Python library
53
+
54
+ The API accepts strings, digit tuples, integers, floats, and `fractions.Fraction` values. Use strings or `Fraction` to express exact decimal values without float representation concerns.
55
+
56
+ ```python
57
+ from baseconvert import base
58
+
59
+ base("FF0.8", 16, 10, string=True) # '4080.5'
60
+ base("4080.5", 10, 16, string=True) # 'FF0.8'
61
+ base("-0.1", 3, 10, string=True, exact=True) # '-0.[3]'
62
+ ```
63
+
64
+ The command-line interface reads a number argument or standard input. Bases are integers; `-s` prints a string, and `--no-recurring` disables recurring notation:
65
+
66
+ ```sh
67
+ python -m baseconvert -n 4080.5 -i 10 -o 16 -s
68
+ echo 0.1 | python -m baseconvert -i 3 -o 10 --no-recurring -s
69
+ ```
70
+
71
+ ## Digits, recurring fractions, and precision
72
+
73
+ String digits are `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`. Values above 61 use ascending Unicode characters; tuple representation is recommended for bases above 61. In a digit tuple, each digit is a base-10 integer and the radix point is `'.'`. A leading `'-'` represents a negative value.
74
+
75
+ Recurring digits are enclosed in square brackets, for example `0.[3]`. `max_depth` limits fractional digits (default 10). Set `exact=True` or `max_depth=0` to calculate the complete terminating or repeating expansion when recurring output is enabled. Exact recurring detection uses rational remainders. With recurring output disabled, an unlimited expansion is bounded by `MAX_DEPTH`.
@@ -0,0 +1,90 @@
1
+ baseconvert
2
+ ===========
3
+
4
+ Convert rational numbers between positive integer bases, with exact
5
+ arithmetic and recurring fractional digits.
6
+
7
+ Requires Python 3.10 or newer.
8
+
9
+ Install
10
+ -------
11
+
12
+ Install the library from PyPI::
13
+
14
+ python -m pip install baseconvert
15
+
16
+ For the GUI, install the optional dependencies and launch the application::
17
+
18
+ python -m pip install 'baseconvert[gui]'
19
+ baseconvert
20
+
21
+ Run from a source checkout
22
+ --------------------------
23
+
24
+ Install `just <https://just.systems/>`_, clone the repository, and run
25
+ ``just launch``. The recipe creates ``.venv`` and installs the GUI extra if
26
+ the launcher or PySide6 QML module is missing, then starts the GUI::
27
+
28
+ git clone https://github.com/BreadMakesYouFull/baseconvert.git
29
+ cd baseconvert
30
+ just launch
31
+
32
+ Development recipes
33
+ -------------------
34
+
35
+ Run these recipes from the repository root::
36
+
37
+ just install # editable install in .venv
38
+ just install-gui # editable install with GUI dependencies
39
+ just install-dev # install build, Black, and Twine
40
+ just format # format Python source
41
+ just lint # check formatting
42
+ just test # run doctests
43
+ just check # lint, doctests, then check files already in dist/
44
+ just build # clean, install development tools, build sdist and wheel
45
+ just clean # remove build artifacts AND .venv
46
+
47
+ ``just build`` first runs ``just clean``, which also deletes ``.venv``, and
48
+ then installs the build tools again. ``just check`` does not build
49
+ distributions; it runs ``twine check dist/*`` against files already in
50
+ ``dist/``. ``just publish-test`` and ``just publish`` run ``just check`` and
51
+ upload the existing ``dist/*`` files to TestPyPI or PyPI, respectively. To
52
+ build and validate distributions before publishing, run ``just build``
53
+ followed by ``just check`` and review the files in ``dist/``.
54
+
55
+ Python library
56
+ --------------
57
+
58
+ The API accepts strings, digit tuples, integers, floats, and
59
+ ``fractions.Fraction`` values. Use strings or ``Fraction`` to express exact
60
+ decimal values without float representation concerns::
61
+
62
+ from baseconvert import base
63
+
64
+ base("FF0.8", 16, 10, string=True) # '4080.5'
65
+ base("4080.5", 10, 16, string=True) # 'FF0.8'
66
+ base("-0.1", 3, 10, string=True, exact=True) # '-0.[3]'
67
+
68
+ The command-line interface reads a number argument or standard input. Bases
69
+ are integers; ``-s`` prints a string, and ``--no-recurring`` disables
70
+ recurring notation::
71
+
72
+ python -m baseconvert -n 4080.5 -i 10 -o 16 -s
73
+ echo 0.1 | python -m baseconvert -i 3 -o 10 --no-recurring -s
74
+
75
+ Digits, recurring fractions, and precision
76
+ ------------------------------------------
77
+
78
+ String digits are
79
+ ``0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz``. Values
80
+ above 61 use ascending Unicode characters; tuple representation is
81
+ recommended for bases above 61. In a digit tuple, each digit is a base-10
82
+ integer and the radix point is ``'.'``. A leading ``'-'`` represents a
83
+ negative value.
84
+
85
+ Recurring digits are enclosed in square brackets, for example ``0.[3]``.
86
+ ``max_depth`` limits fractional digits (default 10). Set ``exact=True`` or
87
+ ``max_depth=0`` to calculate the complete terminating or repeating expansion
88
+ when recurring output is enabled. Exact recurring detection uses rational
89
+ remainders. With recurring output disabled, an unlimited expansion is bounded
90
+ by ``MAX_DEPTH``.
@@ -0,0 +1 @@
1
+ 2.1.1
@@ -0,0 +1,80 @@
1
+ import QtQuick
2
+ import QtQuick.Controls
3
+ import QtQuick.Layouts
4
+
5
+ Item {
6
+ id: buttonRow
7
+ property string text1: "1"
8
+ property string text2: "2"
9
+ property string text3: "3"
10
+ property string text4: "4"
11
+ property string text5: "5"
12
+ property string text6: "6"
13
+ property bool enable1: true
14
+ property bool enable2: true
15
+ property bool enable3: true
16
+ property bool enable4: true
17
+ property bool enable5: true
18
+ property bool enable6: true
19
+ signal buttonPressed(text: string)
20
+ property bool darkMode: false
21
+ property color color1: darkMode ? "#d8dfd2" : "#f0f0df"
22
+ property color colorText1: "#18211e"
23
+ property color color2: color1
24
+ property color colorText2: colorText1
25
+ property color color3: color1
26
+ property color colorText3: colorText1
27
+ property color color4: color1
28
+ property color colorText4: colorText1
29
+ property color color5: color1
30
+ property color colorText5: colorText1
31
+ property color color6: color1
32
+ property color colorText6: colorText1
33
+
34
+ RowLayout {
35
+ anchors.fill: parent
36
+ spacing: 4
37
+
38
+ Repeater {
39
+ model: 6
40
+ delegate: Button {
41
+ required property int index
42
+ property bool enabledKey: index === 0 ? buttonRow.enable1
43
+ : index === 1 ? buttonRow.enable2
44
+ : index === 2 ? buttonRow.enable3
45
+ : index === 3 ? buttonRow.enable4
46
+ : index === 4 ? buttonRow.enable5 : buttonRow.enable6
47
+ property string keyText: index === 0 ? buttonRow.text1
48
+ : index === 1 ? buttonRow.text2
49
+ : index === 2 ? buttonRow.text3
50
+ : index === 3 ? buttonRow.text4
51
+ : index === 4 ? buttonRow.text5 : buttonRow.text6
52
+ property color keyColor: index === 0 ? buttonRow.color1
53
+ : index === 1 ? buttonRow.color2
54
+ : index === 2 ? buttonRow.color3
55
+ : index === 3 ? buttonRow.color4
56
+ : index === 4 ? buttonRow.color5 : buttonRow.color6
57
+ property color keyTextColor: index === 0 ? buttonRow.colorText1
58
+ : index === 1 ? buttonRow.colorText2
59
+ : index === 2 ? buttonRow.colorText3
60
+ : index === 3 ? buttonRow.colorText4
61
+ : index === 4 ? buttonRow.colorText5 : buttonRow.colorText6
62
+ visible: enabledKey
63
+ Layout.fillWidth: true
64
+ Layout.fillHeight: true
65
+ text: keyText
66
+ font.family: "Monospace"
67
+ font.weight: Font.Bold
68
+ onClicked: buttonRow.buttonPressed(text)
69
+ palette.button: keyColor
70
+ palette.buttonText: keyTextColor
71
+ background: Rectangle {
72
+ radius: Math.min(8, height * 0.22)
73
+ color: parent.down ? Qt.darker(parent.keyColor, 1.12) : parent.keyColor
74
+ border.width: 1
75
+ border.color: buttonRow.darkMode ? "#f5f4e5" : "#ffffff"
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,13 @@
1
+ from baseconvert.baseconvert import BaseConverter
2
+ from baseconvert.baseconvert import DigitTuple
3
+ from baseconvert.baseconvert import base
4
+
5
+ from importlib.metadata import PackageNotFoundError, version
6
+
7
+ __all__ = ["BaseConverter", "DigitTuple", "base", "__version__"]
8
+
9
+ try:
10
+ __version__ = version("baseconvert")
11
+ except PackageNotFoundError:
12
+ # Allow imports directly from a source checkout before installation.
13
+ __version__ = "0+unknown"
@@ -0,0 +1,90 @@
1
+ """Convert a number from the command line, or launch the GUI with no input.
2
+
3
+ Examples::
4
+
5
+ python -m baseconvert -n 0.5 -i 10 -o 20 -s
6
+ echo 3.1415926 | python -m baseconvert -i 10 -o 16 -d 3 -s
7
+ python -m baseconvert -n 0.1 -i 3 -o 10 --no-recurring -s
8
+ baseconvert --theme light
9
+ """
10
+
11
+ import argparse
12
+ import sys
13
+ from typing import Sequence
14
+
15
+ from baseconvert import DigitTuple, base
16
+
17
+
18
+ def main(argv: Sequence[str] | None = None) -> str | DigitTuple | None:
19
+ parser = argparse.ArgumentParser(
20
+ description="Convert rational numbers between bases."
21
+ )
22
+ parser.add_argument(
23
+ "-n",
24
+ "--number",
25
+ default=None,
26
+ help="The number to convert as a string; otherwise read stdin.",
27
+ )
28
+ parser.add_argument(
29
+ "-i", "--input-base", type=int, default=10, help="Input base (default: 10)."
30
+ )
31
+ parser.add_argument(
32
+ "-o", "--output-base", type=int, default=10, help="Output base (default: 10)."
33
+ )
34
+ parser.add_argument(
35
+ "-d",
36
+ "--max-depth",
37
+ type=int,
38
+ default=10,
39
+ help="Maximum fractional digits (default: 10).",
40
+ )
41
+ parser.add_argument(
42
+ "--theme",
43
+ choices=("system", "light", "dark"),
44
+ default="dark",
45
+ help="GUI color theme (default: dark).",
46
+ )
47
+ recurring = parser.add_mutually_exclusive_group()
48
+ recurring.add_argument(
49
+ "-r",
50
+ "--recurring",
51
+ dest="recurring",
52
+ action="store_true",
53
+ help="Mark repeating fractional digits (the default).",
54
+ )
55
+ recurring.add_argument(
56
+ "--no-recurring",
57
+ dest="recurring",
58
+ action="store_false",
59
+ help="Do not mark repeating fractional digits.",
60
+ )
61
+ parser.set_defaults(recurring=True)
62
+ parser.add_argument(
63
+ "-s",
64
+ "--string",
65
+ action="store_true",
66
+ help="Output the number as a string rather than a tuple.",
67
+ )
68
+ args = parser.parse_args(argv)
69
+
70
+ options = {
71
+ "string": args.string,
72
+ "max_depth": args.max_depth,
73
+ "recurring": args.recurring,
74
+ }
75
+ if args.number is not None:
76
+ return base(args.number, args.input_base, args.output_base, **options)
77
+ if not sys.stdin.isatty():
78
+ number = sys.stdin.read().strip()
79
+ return base(number, args.input_base, args.output_base, **options)
80
+
81
+ from .gui import main as gui_main
82
+
83
+ gui_main(theme=args.theme)
84
+ return None
85
+
86
+
87
+ if __name__ == "__main__":
88
+ result = main()
89
+ if result is not None:
90
+ print(result)