chiranjeev-toolkit 1.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chiranjeev (Roll No. 2432709)
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,91 @@
1
+ Metadata-Version: 2.4
2
+ Name: chiranjeev-toolkit
3
+ Version: 1.0.0
4
+ Summary: A tiny, dependency-free Python toolkit with math, text and statistics helpers, plus a beautiful terminal UI.
5
+ Author: Chiranjeev
6
+ License: MIT
7
+ Keywords: toolkit,math,text,statistics,cli,assignment
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Education
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ <div align="center">
18
+
19
+ # ๐Ÿงฐ chiranjeev-toolkit
20
+
21
+ **A tiny, dependency-free Python toolkit โ€” math, text & statistics helpers with a beautiful terminal UI.**
22
+
23
+ ![python](https://img.shields.io/badge/python-3.8%2B-blue)
24
+ ![license](https://img.shields.io/badge/license-MIT-green)
25
+ ![deps](https://img.shields.io/badge/dependencies-zero-brightgreen)
26
+
27
+ Made by **Chiranjeev** ยท Roll No. **2432709**
28
+
29
+ </div>
30
+
31
+ ---
32
+
33
+ ## โœจ Features
34
+
35
+ | Module | What it gives you |
36
+ | --- | --- |
37
+ | `ctoolkit.mathx` | `is_prime`, `primes_upto`, `prime_factors`, `fibonacci`, `factorial`, `gcd`, `lcm`, `collatz_steps` |
38
+ | `ctoolkit.textx` | `word_count`, `vowel_count`, `is_palindrome`, `reverse_words`, `caesar`, `slugify` |
39
+ | `ctoolkit.stats` | `mean`, `median`, `mode`, `variance`, `std_dev`, `describe` |
40
+ | `ctoolkit.display` | `box`, `table`, `banner`, `paint` โ€” ANSI colours that respect `NO_COLOR` |
41
+
42
+ ## ๐Ÿ“ฆ Installation
43
+
44
+ ```bash
45
+ pip install chiranjeev-toolkit
46
+ # or from source
47
+ pip install .
48
+ ```
49
+
50
+ ## ๐Ÿš€ Quick start
51
+
52
+ ```python
53
+ import ctoolkit as ct
54
+
55
+ ct.is_prime(97) # True
56
+ ct.prime_factors(360) # [2, 2, 2, 3, 3, 5]
57
+ ct.fibonacci(8) # [0, 1, 1, 2, 3, 5, 8, 13]
58
+ ct.caesar("Hello", 3) # 'Khoor'
59
+ ct.describe([2, 4, 4, 4, 5, 5, 7, 9])["std_dev"] # 2.0
60
+ ```
61
+
62
+ ## ๐Ÿ–ฅ๏ธ Command line
63
+
64
+ ```bash
65
+ ctoolkit info # banner + author details
66
+ ctoolkit prime 97 # primality + factorisation
67
+ ctoolkit fib 10 # first 10 Fibonacci numbers
68
+ ctoolkit primes 50 # all primes up to 50
69
+ ctoolkit stats 2 4 4 4 5 5 7 9 # descriptive statistics table
70
+ ctoolkit text "Never odd or even"
71
+ ```
72
+
73
+ (`python -m ctoolkit ...` works too.)
74
+
75
+ ## ๐Ÿงช Run the tests
76
+
77
+ ```bash
78
+ python -m unittest discover -s tests
79
+ ```
80
+
81
+ ## ๐Ÿ“ค Publishing to PyPI
82
+
83
+ ```bash
84
+ pip install build twine
85
+ python -m build
86
+ twine upload dist/*
87
+ ```
88
+
89
+ ## ๐Ÿ“„ License
90
+
91
+ MIT ยฉ 2026 Chiranjeev (Roll No. 2432709)
@@ -0,0 +1,75 @@
1
+ <div align="center">
2
+
3
+ # ๐Ÿงฐ chiranjeev-toolkit
4
+
5
+ **A tiny, dependency-free Python toolkit โ€” math, text & statistics helpers with a beautiful terminal UI.**
6
+
7
+ ![python](https://img.shields.io/badge/python-3.8%2B-blue)
8
+ ![license](https://img.shields.io/badge/license-MIT-green)
9
+ ![deps](https://img.shields.io/badge/dependencies-zero-brightgreen)
10
+
11
+ Made by **Chiranjeev** ยท Roll No. **2432709**
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## โœจ Features
18
+
19
+ | Module | What it gives you |
20
+ | --- | --- |
21
+ | `ctoolkit.mathx` | `is_prime`, `primes_upto`, `prime_factors`, `fibonacci`, `factorial`, `gcd`, `lcm`, `collatz_steps` |
22
+ | `ctoolkit.textx` | `word_count`, `vowel_count`, `is_palindrome`, `reverse_words`, `caesar`, `slugify` |
23
+ | `ctoolkit.stats` | `mean`, `median`, `mode`, `variance`, `std_dev`, `describe` |
24
+ | `ctoolkit.display` | `box`, `table`, `banner`, `paint` โ€” ANSI colours that respect `NO_COLOR` |
25
+
26
+ ## ๐Ÿ“ฆ Installation
27
+
28
+ ```bash
29
+ pip install chiranjeev-toolkit
30
+ # or from source
31
+ pip install .
32
+ ```
33
+
34
+ ## ๐Ÿš€ Quick start
35
+
36
+ ```python
37
+ import ctoolkit as ct
38
+
39
+ ct.is_prime(97) # True
40
+ ct.prime_factors(360) # [2, 2, 2, 3, 3, 5]
41
+ ct.fibonacci(8) # [0, 1, 1, 2, 3, 5, 8, 13]
42
+ ct.caesar("Hello", 3) # 'Khoor'
43
+ ct.describe([2, 4, 4, 4, 5, 5, 7, 9])["std_dev"] # 2.0
44
+ ```
45
+
46
+ ## ๐Ÿ–ฅ๏ธ Command line
47
+
48
+ ```bash
49
+ ctoolkit info # banner + author details
50
+ ctoolkit prime 97 # primality + factorisation
51
+ ctoolkit fib 10 # first 10 Fibonacci numbers
52
+ ctoolkit primes 50 # all primes up to 50
53
+ ctoolkit stats 2 4 4 4 5 5 7 9 # descriptive statistics table
54
+ ctoolkit text "Never odd or even"
55
+ ```
56
+
57
+ (`python -m ctoolkit ...` works too.)
58
+
59
+ ## ๐Ÿงช Run the tests
60
+
61
+ ```bash
62
+ python -m unittest discover -s tests
63
+ ```
64
+
65
+ ## ๐Ÿ“ค Publishing to PyPI
66
+
67
+ ```bash
68
+ pip install build twine
69
+ python -m build
70
+ twine upload dist/*
71
+ ```
72
+
73
+ ## ๐Ÿ“„ License
74
+
75
+ MIT ยฉ 2026 Chiranjeev (Roll No. 2432709)
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "chiranjeev-toolkit"
7
+ version = "1.0.0"
8
+ description = "A tiny, dependency-free Python toolkit with math, text and statistics helpers, plus a beautiful terminal UI."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Chiranjeev" }]
13
+ keywords = ["toolkit", "math", "text", "statistics", "cli", "assignment"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Intended Audience :: Education",
19
+ ]
20
+
21
+ [project.scripts]
22
+ ctoolkit = "ctoolkit.cli:main"
23
+
24
+ [tool.setuptools.packages.find]
25
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.4
2
+ Name: chiranjeev-toolkit
3
+ Version: 1.0.0
4
+ Summary: A tiny, dependency-free Python toolkit with math, text and statistics helpers, plus a beautiful terminal UI.
5
+ Author: Chiranjeev
6
+ License: MIT
7
+ Keywords: toolkit,math,text,statistics,cli,assignment
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Education
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ <div align="center">
18
+
19
+ # ๐Ÿงฐ chiranjeev-toolkit
20
+
21
+ **A tiny, dependency-free Python toolkit โ€” math, text & statistics helpers with a beautiful terminal UI.**
22
+
23
+ ![python](https://img.shields.io/badge/python-3.8%2B-blue)
24
+ ![license](https://img.shields.io/badge/license-MIT-green)
25
+ ![deps](https://img.shields.io/badge/dependencies-zero-brightgreen)
26
+
27
+ Made by **Chiranjeev** ยท Roll No. **2432709**
28
+
29
+ </div>
30
+
31
+ ---
32
+
33
+ ## โœจ Features
34
+
35
+ | Module | What it gives you |
36
+ | --- | --- |
37
+ | `ctoolkit.mathx` | `is_prime`, `primes_upto`, `prime_factors`, `fibonacci`, `factorial`, `gcd`, `lcm`, `collatz_steps` |
38
+ | `ctoolkit.textx` | `word_count`, `vowel_count`, `is_palindrome`, `reverse_words`, `caesar`, `slugify` |
39
+ | `ctoolkit.stats` | `mean`, `median`, `mode`, `variance`, `std_dev`, `describe` |
40
+ | `ctoolkit.display` | `box`, `table`, `banner`, `paint` โ€” ANSI colours that respect `NO_COLOR` |
41
+
42
+ ## ๐Ÿ“ฆ Installation
43
+
44
+ ```bash
45
+ pip install chiranjeev-toolkit
46
+ # or from source
47
+ pip install .
48
+ ```
49
+
50
+ ## ๐Ÿš€ Quick start
51
+
52
+ ```python
53
+ import ctoolkit as ct
54
+
55
+ ct.is_prime(97) # True
56
+ ct.prime_factors(360) # [2, 2, 2, 3, 3, 5]
57
+ ct.fibonacci(8) # [0, 1, 1, 2, 3, 5, 8, 13]
58
+ ct.caesar("Hello", 3) # 'Khoor'
59
+ ct.describe([2, 4, 4, 4, 5, 5, 7, 9])["std_dev"] # 2.0
60
+ ```
61
+
62
+ ## ๐Ÿ–ฅ๏ธ Command line
63
+
64
+ ```bash
65
+ ctoolkit info # banner + author details
66
+ ctoolkit prime 97 # primality + factorisation
67
+ ctoolkit fib 10 # first 10 Fibonacci numbers
68
+ ctoolkit primes 50 # all primes up to 50
69
+ ctoolkit stats 2 4 4 4 5 5 7 9 # descriptive statistics table
70
+ ctoolkit text "Never odd or even"
71
+ ```
72
+
73
+ (`python -m ctoolkit ...` works too.)
74
+
75
+ ## ๐Ÿงช Run the tests
76
+
77
+ ```bash
78
+ python -m unittest discover -s tests
79
+ ```
80
+
81
+ ## ๐Ÿ“ค Publishing to PyPI
82
+
83
+ ```bash
84
+ pip install build twine
85
+ python -m build
86
+ twine upload dist/*
87
+ ```
88
+
89
+ ## ๐Ÿ“„ License
90
+
91
+ MIT ยฉ 2026 Chiranjeev (Roll No. 2432709)
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/chiranjeev_toolkit.egg-info/PKG-INFO
5
+ src/chiranjeev_toolkit.egg-info/SOURCES.txt
6
+ src/chiranjeev_toolkit.egg-info/dependency_links.txt
7
+ src/chiranjeev_toolkit.egg-info/entry_points.txt
8
+ src/chiranjeev_toolkit.egg-info/top_level.txt
9
+ src/ctoolkit/__init__.py
10
+ src/ctoolkit/__main__.py
11
+ src/ctoolkit/cli.py
12
+ src/ctoolkit/display.py
13
+ src/ctoolkit/mathx.py
14
+ src/ctoolkit/stats.py
15
+ src/ctoolkit/textx.py
16
+ tests/test_ctoolkit.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ctoolkit = ctoolkit.cli:main
@@ -0,0 +1,38 @@
1
+ """ctoolkit - a tiny toolkit of math, text and statistics helpers.
2
+
3
+ Author : Chiranjeev
4
+ Roll No: 2432709
5
+ """
6
+
7
+ from .mathx import (
8
+ collatz_steps,
9
+ factorial,
10
+ fibonacci,
11
+ gcd,
12
+ is_prime,
13
+ lcm,
14
+ prime_factors,
15
+ primes_upto,
16
+ )
17
+ from .stats import describe, mean, median, mode, std_dev, variance
18
+ from .textx import (
19
+ caesar,
20
+ is_palindrome,
21
+ reverse_words,
22
+ slugify,
23
+ vowel_count,
24
+ word_count,
25
+ )
26
+
27
+ __version__ = "1.0.0"
28
+ __author__ = "Chiranjeev"
29
+ __roll_no__ = "2432709"
30
+
31
+ __all__ = [
32
+ "__version__", "__author__", "__roll_no__",
33
+ "collatz_steps", "factorial", "fibonacci", "gcd", "is_prime", "lcm",
34
+ "prime_factors", "primes_upto",
35
+ "describe", "mean", "median", "mode", "std_dev", "variance",
36
+ "caesar", "is_palindrome", "reverse_words", "slugify", "vowel_count",
37
+ "word_count",
38
+ ]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,86 @@
1
+ """Command-line interface: ``ctoolkit <command>`` or ``python -m ctoolkit``."""
2
+
3
+ import argparse
4
+ from typing import List, Optional
5
+
6
+ from . import __version__, mathx, stats, textx
7
+ from .display import banner, box, paint, table
8
+
9
+
10
+ def _build_parser() -> argparse.ArgumentParser:
11
+ p = argparse.ArgumentParser(
12
+ prog="ctoolkit",
13
+ description="Math, text and statistics helpers with a pretty terminal UI.",
14
+ )
15
+ p.add_argument("-V", "--version", action="version", version=f"ctoolkit {__version__}")
16
+ sub = p.add_subparsers(dest="command")
17
+
18
+ sub.add_parser("info", help="show the banner and author details")
19
+
20
+ s = sub.add_parser("prime", help="primality check and factorisation")
21
+ s.add_argument("n", type=int)
22
+
23
+ s = sub.add_parser("fib", help="first N Fibonacci numbers")
24
+ s.add_argument("count", type=int)
25
+
26
+ s = sub.add_parser("primes", help="all primes up to N")
27
+ s.add_argument("n", type=int)
28
+
29
+ s = sub.add_parser("stats", help="descriptive statistics for numbers")
30
+ s.add_argument("numbers", type=float, nargs="+")
31
+
32
+ s = sub.add_parser("text", help="analyse a piece of text")
33
+ s.add_argument("text", nargs="+")
34
+
35
+ return p
36
+
37
+
38
+ def _fmt(x: float) -> str:
39
+ return f"{x:.4g}" if isinstance(x, float) else str(x)
40
+
41
+
42
+ def main(argv: Optional[List[str]] = None) -> int:
43
+ parser = _build_parser()
44
+ args = parser.parse_args(argv)
45
+
46
+ try:
47
+ if args.command in (None, "info"):
48
+ print(banner())
49
+ if args.command is None:
50
+ print("\nRun " + paint("ctoolkit --help", "yellow") + " to see all commands.")
51
+ elif args.command == "prime":
52
+ ok = mathx.is_prime(args.n)
53
+ verdict = paint("PRIME โœ”", "green", "bold") if ok else paint("NOT PRIME โœ˜", "red", "bold")
54
+ lines = [f"{args.n} is {verdict}"]
55
+ if args.n >= 2:
56
+ lines.append("Factors: " + " ร— ".join(map(str, mathx.prime_factors(args.n))))
57
+ print(box(lines, "green" if ok else "red"))
58
+ elif args.command == "fib":
59
+ seq = mathx.fibonacci(args.count)
60
+ print(box([", ".join(map(str, seq)) or "(empty)"], "cyan"))
61
+ elif args.command == "primes":
62
+ ps = mathx.primes_upto(args.n)
63
+ print(box([f"{len(ps)} primes up to {args.n}", ", ".join(map(str, ps))], "blue"))
64
+ elif args.command == "stats":
65
+ d = stats.describe(args.numbers)
66
+ rows = [(k, ", ".join(map(_fmt, v)) if isinstance(v, list) else _fmt(v)) for k, v in d.items()]
67
+ print(table(["Metric", "Value"], rows, "magenta"))
68
+ elif args.command == "text":
69
+ t = " ".join(args.text)
70
+ rows = [
71
+ ("Words", textx.word_count(t)),
72
+ ("Vowels", textx.vowel_count(t)),
73
+ ("Palindrome", "yes" if textx.is_palindrome(t) else "no"),
74
+ ("Reversed words", textx.reverse_words(t)),
75
+ ("Slug", textx.slugify(t)),
76
+ ("Caesar +3", textx.caesar(t, 3)),
77
+ ]
78
+ print(table(["Property", "Result"], rows, "cyan"))
79
+ except (ValueError, TypeError) as exc:
80
+ print(paint(f"Error: {exc}", "red"))
81
+ return 1
82
+ return 0
83
+
84
+
85
+ if __name__ == "__main__":
86
+ raise SystemExit(main())
@@ -0,0 +1,80 @@
1
+ """Tiny ANSI helpers for a beautiful terminal UI (respects NO_COLOR)."""
2
+
3
+ import os
4
+ import sys
5
+ from typing import Iterable, List, Sequence
6
+
7
+ _CODES = {
8
+ "reset": "0", "bold": "1", "dim": "2",
9
+ "red": "91", "green": "92", "yellow": "93",
10
+ "blue": "94", "magenta": "95", "cyan": "96",
11
+ }
12
+
13
+
14
+ def _use_color() -> bool:
15
+ return sys.stdout.isatty() and "NO_COLOR" not in os.environ
16
+
17
+
18
+ def paint(text: str, *styles: str) -> str:
19
+ """Wrap ``text`` in ANSI styles (no-op when colour is unavailable)."""
20
+ if not _use_color():
21
+ return text
22
+ start = "".join(f"\033[{_CODES[s]}m" for s in styles)
23
+ return f"{start}{text}\033[0m"
24
+
25
+
26
+ def box(lines: Iterable[str], color: str = "cyan") -> str:
27
+ """Draw a rounded box around ``lines``."""
28
+ rows = list(lines)
29
+ width = max((len(r) for r in rows), default=0)
30
+ top = paint("โ•ญ" + "โ”€" * (width + 2) + "โ•ฎ", color)
31
+ bottom = paint("โ•ฐ" + "โ”€" * (width + 2) + "โ•ฏ", color)
32
+ side = paint("โ”‚", color)
33
+ body = [f"{side} {r.ljust(width)} {side}" for r in rows]
34
+ return "\n".join([top, *body, bottom])
35
+
36
+
37
+ def table(headers: Sequence[str], rows: Sequence[Sequence[object]], color: str = "cyan") -> str:
38
+ """Render a neat unicode table."""
39
+ str_rows: List[List[str]] = [[str(c) for c in r] for r in rows]
40
+ widths = [
41
+ max(len(h), *(len(r[i]) for r in str_rows)) if str_rows else len(h)
42
+ for i, h in enumerate(headers)
43
+ ]
44
+
45
+ def line(left: str, mid: str, right: str) -> str:
46
+ return paint(left + mid.join("โ”€" * (w + 2) for w in widths) + right, color)
47
+
48
+ def row(cells: Sequence[str], style: str = "") -> str:
49
+ bar = paint("โ”‚", color)
50
+ parts = [f" {paint(c.ljust(w), style) if style else c.ljust(w)} " for c, w in zip(cells, widths)]
51
+ return bar + bar.join(parts) + bar
52
+
53
+ out = [line("โ”Œ", "โ”ฌ", "โ”"), row(list(headers), "bold"), line("โ”œ", "โ”ผ", "โ”ค")]
54
+ out += [row(r) for r in str_rows]
55
+ out.append(line("โ””", "โ”ด", "โ”˜"))
56
+ return "\n".join(out)
57
+
58
+
59
+ def banner() -> str:
60
+ """The package banner."""
61
+ from . import __author__, __roll_no__, __version__
62
+
63
+ art = [
64
+ " ____ _____ ___ ___ _ _ _____ _____ ",
65
+ " / ___|_ _/ _ \\ / _ \\| | | |/ /_ _|_ _|",
66
+ "| | | || | | | | | | | | ' / | | | | ",
67
+ "| |___ | || |_| | |_| | |___| . \\ | | | | ",
68
+ " \\____| |_| \\___/ \\___/|_____|_|\\_\\___| |_| ",
69
+ ]
70
+ colors = ["cyan", "cyan", "blue", "blue", "magenta"]
71
+ art_block = "\n".join(paint(l, c, "bold") for l, c in zip(art, colors))
72
+ info = box(
73
+ [
74
+ f"Author : {__author__}",
75
+ f"Roll No : {__roll_no__}",
76
+ f"Version : {__version__}",
77
+ ],
78
+ "magenta",
79
+ )
80
+ return f"{art_block}\n{info}"
@@ -0,0 +1,101 @@
1
+ """Number-theory and math helpers."""
2
+
3
+ from typing import List
4
+
5
+
6
+ def _check_int(n: int, name: str = "n", minimum: int = 0) -> None:
7
+ if not isinstance(n, int) or isinstance(n, bool):
8
+ raise TypeError(f"{name} must be an int, got {type(n).__name__}")
9
+ if n < minimum:
10
+ raise ValueError(f"{name} must be >= {minimum}, got {n}")
11
+
12
+
13
+ def is_prime(n: int) -> bool:
14
+ """Return True if ``n`` is a prime number."""
15
+ _check_int(n, minimum=-(10**18))
16
+ if n < 2:
17
+ return False
18
+ if n < 4:
19
+ return True
20
+ if n % 2 == 0 or n % 3 == 0:
21
+ return False
22
+ i = 5
23
+ while i * i <= n:
24
+ if n % i == 0 or n % (i + 2) == 0:
25
+ return False
26
+ i += 6
27
+ return True
28
+
29
+
30
+ def primes_upto(n: int) -> List[int]:
31
+ """Return all primes <= n using the Sieve of Eratosthenes."""
32
+ _check_int(n)
33
+ if n < 2:
34
+ return []
35
+ sieve = bytearray([1]) * (n + 1)
36
+ sieve[0:2] = b"\x00\x00"
37
+ for i in range(2, int(n ** 0.5) + 1):
38
+ if sieve[i]:
39
+ sieve[i * i :: i] = bytearray(len(range(i * i, n + 1, i)))
40
+ return [i for i, flag in enumerate(sieve) if flag]
41
+
42
+
43
+ def prime_factors(n: int) -> List[int]:
44
+ """Return the prime factorisation of ``n`` (with repetition)."""
45
+ _check_int(n, minimum=2)
46
+ factors, d = [], 2
47
+ while d * d <= n:
48
+ while n % d == 0:
49
+ factors.append(d)
50
+ n //= d
51
+ d += 1 if d == 2 else 2
52
+ if n > 1:
53
+ factors.append(n)
54
+ return factors
55
+
56
+
57
+ def fibonacci(count: int) -> List[int]:
58
+ """Return the first ``count`` Fibonacci numbers."""
59
+ _check_int(count, "count")
60
+ seq: List[int] = []
61
+ a, b = 0, 1
62
+ for _ in range(count):
63
+ seq.append(a)
64
+ a, b = b, a + b
65
+ return seq
66
+
67
+
68
+ def factorial(n: int) -> int:
69
+ """Return n! (iteratively, so no recursion limit)."""
70
+ _check_int(n)
71
+ result = 1
72
+ for i in range(2, n + 1):
73
+ result *= i
74
+ return result
75
+
76
+
77
+ def gcd(a: int, b: int) -> int:
78
+ """Greatest common divisor (Euclid's algorithm)."""
79
+ _check_int(a, "a", minimum=-(10**18))
80
+ _check_int(b, "b", minimum=-(10**18))
81
+ a, b = abs(a), abs(b)
82
+ while b:
83
+ a, b = b, a % b
84
+ return a
85
+
86
+
87
+ def lcm(a: int, b: int) -> int:
88
+ """Least common multiple."""
89
+ if a == 0 or b == 0:
90
+ return 0
91
+ return abs(a * b) // gcd(a, b)
92
+
93
+
94
+ def collatz_steps(n: int) -> int:
95
+ """Number of steps for ``n`` to reach 1 in the Collatz sequence."""
96
+ _check_int(n, minimum=1)
97
+ steps = 0
98
+ while n != 1:
99
+ n = n // 2 if n % 2 == 0 else 3 * n + 1
100
+ steps += 1
101
+ return steps
@@ -0,0 +1,59 @@
1
+ """Descriptive statistics without any third-party dependency."""
2
+
3
+ import math
4
+ from collections import Counter
5
+ from typing import Dict, List, Sequence
6
+
7
+
8
+ def _prepare(data: Sequence[float]) -> List[float]:
9
+ values = list(data)
10
+ if not values:
11
+ raise ValueError("data must not be empty")
12
+ return values
13
+
14
+
15
+ def mean(data: Sequence[float]) -> float:
16
+ values = _prepare(data)
17
+ return sum(values) / len(values)
18
+
19
+
20
+ def median(data: Sequence[float]) -> float:
21
+ values = sorted(_prepare(data))
22
+ mid = len(values) // 2
23
+ if len(values) % 2:
24
+ return float(values[mid])
25
+ return (values[mid - 1] + values[mid]) / 2
26
+
27
+
28
+ def mode(data: Sequence[float]) -> List[float]:
29
+ """Return every most-frequent value (sorted)."""
30
+ counts = Counter(_prepare(data))
31
+ top = max(counts.values())
32
+ return sorted(v for v, c in counts.items() if c == top)
33
+
34
+
35
+ def variance(data: Sequence[float], sample: bool = False) -> float:
36
+ values = _prepare(data)
37
+ if sample and len(values) < 2:
38
+ raise ValueError("sample variance needs at least two values")
39
+ m = mean(values)
40
+ ss = sum((x - m) ** 2 for x in values)
41
+ return ss / (len(values) - 1 if sample else len(values))
42
+
43
+
44
+ def std_dev(data: Sequence[float], sample: bool = False) -> float:
45
+ return math.sqrt(variance(data, sample))
46
+
47
+
48
+ def describe(data: Sequence[float]) -> Dict[str, object]:
49
+ """Return a summary dictionary of the data."""
50
+ values = _prepare(data)
51
+ return {
52
+ "count": len(values),
53
+ "min": min(values),
54
+ "max": max(values),
55
+ "mean": mean(values),
56
+ "median": median(values),
57
+ "mode": mode(values),
58
+ "std_dev": std_dev(values),
59
+ }
@@ -0,0 +1,42 @@
1
+ """Text-processing helpers."""
2
+
3
+ import re
4
+ import string
5
+
6
+
7
+ def word_count(text: str) -> int:
8
+ """Count the words in ``text``."""
9
+ return len(re.findall(r"\b[\w']+\b", text))
10
+
11
+
12
+ def vowel_count(text: str) -> int:
13
+ """Count the vowels (a, e, i, o, u) in ``text``."""
14
+ return sum(1 for ch in text.lower() if ch in "aeiou")
15
+
16
+
17
+ def is_palindrome(text: str) -> bool:
18
+ """Case-, space- and punctuation-insensitive palindrome check."""
19
+ cleaned = [ch.lower() for ch in text if ch.isalnum()]
20
+ return cleaned == cleaned[::-1]
21
+
22
+
23
+ def reverse_words(text: str) -> str:
24
+ """Reverse the order of the words in ``text``."""
25
+ return " ".join(reversed(text.split()))
26
+
27
+
28
+ def caesar(text: str, shift: int) -> str:
29
+ """Apply a Caesar cipher. Use a negative shift to decrypt."""
30
+ shift %= 26
31
+ lower, upper = string.ascii_lowercase, string.ascii_uppercase
32
+ table = str.maketrans(
33
+ lower + upper,
34
+ lower[shift:] + lower[:shift] + upper[shift:] + upper[:shift],
35
+ )
36
+ return text.translate(table)
37
+
38
+
39
+ def slugify(text: str) -> str:
40
+ """Turn ``text`` into a URL-friendly slug."""
41
+ text = re.sub(r"[^\w\s-]", "", text.lower())
42
+ return re.sub(r"[\s_-]+", "-", text).strip("-")
@@ -0,0 +1,75 @@
1
+ import unittest
2
+
3
+ from ctoolkit import (
4
+ caesar, collatz_steps, describe, factorial, fibonacci, gcd, is_palindrome,
5
+ is_prime, lcm, mean, median, mode, prime_factors, primes_upto, reverse_words,
6
+ slugify, std_dev, vowel_count, word_count,
7
+ )
8
+ import ctoolkit
9
+
10
+
11
+ class TestMath(unittest.TestCase):
12
+ def test_identity(self):
13
+ self.assertEqual(ctoolkit.__author__, "Chiranjeev")
14
+ self.assertEqual(ctoolkit.__roll_no__, "2432709")
15
+
16
+ def test_is_prime(self):
17
+ self.assertEqual([n for n in range(20) if is_prime(n)], [2, 3, 5, 7, 11, 13, 17, 19])
18
+ self.assertFalse(is_prime(-7))
19
+
20
+ def test_primes_upto(self):
21
+ self.assertEqual(primes_upto(30), [2, 3, 5, 7, 11, 13, 17, 19, 23, 29])
22
+ self.assertEqual(primes_upto(1), [])
23
+
24
+ def test_prime_factors(self):
25
+ self.assertEqual(prime_factors(360), [2, 2, 2, 3, 3, 5])
26
+ self.assertEqual(prime_factors(97), [97])
27
+
28
+ def test_fibonacci(self):
29
+ self.assertEqual(fibonacci(8), [0, 1, 1, 2, 3, 5, 8, 13])
30
+ self.assertEqual(fibonacci(0), [])
31
+
32
+ def test_factorial_gcd_lcm(self):
33
+ self.assertEqual(factorial(5), 120)
34
+ self.assertEqual(gcd(48, 18), 6)
35
+ self.assertEqual(lcm(4, 6), 12)
36
+
37
+ def test_collatz(self):
38
+ self.assertEqual(collatz_steps(27), 111)
39
+
40
+ def test_errors(self):
41
+ with self.assertRaises(ValueError):
42
+ factorial(-1)
43
+ with self.assertRaises(TypeError):
44
+ fibonacci("3")
45
+
46
+
47
+ class TestText(unittest.TestCase):
48
+ def test_basic(self):
49
+ self.assertEqual(word_count("Hello, world! It's me."), 4)
50
+ self.assertEqual(vowel_count("Chiranjeev"), 4)
51
+ self.assertTrue(is_palindrome("A man, a plan, a canal: Panama"))
52
+ self.assertEqual(reverse_words("one two three"), "three two one")
53
+ self.assertEqual(slugify("Hello, World! 2026"), "hello-world-2026")
54
+
55
+ def test_caesar_roundtrip(self):
56
+ self.assertEqual(caesar("Hello, World!", 3), "Khoor, Zruog!")
57
+ self.assertEqual(caesar(caesar("Hello", 7), -7), "Hello")
58
+
59
+
60
+ class TestStats(unittest.TestCase):
61
+ def test_stats(self):
62
+ data = [2, 4, 4, 4, 5, 5, 7, 9]
63
+ self.assertEqual(mean(data), 5)
64
+ self.assertEqual(median(data), 4.5)
65
+ self.assertEqual(mode(data), [4])
66
+ self.assertEqual(std_dev(data), 2)
67
+ self.assertEqual(describe(data)["count"], 8)
68
+
69
+ def test_empty(self):
70
+ with self.assertRaises(ValueError):
71
+ mean([])
72
+
73
+
74
+ if __name__ == "__main__":
75
+ unittest.main()