numclassify 0.2.0__tar.gz → 0.2.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 (86) hide show
  1. {numclassify-0.2.0 → numclassify-0.2.1}/.gitignore +1 -0
  2. numclassify-0.2.1/CONTRIBUTING.md +71 -0
  3. {numclassify-0.2.0 → numclassify-0.2.1}/PKG-INFO +5 -3
  4. numclassify-0.2.1/examples/basic_usage.py +6 -0
  5. numclassify-0.2.1/examples/custom_type.py +12 -0
  6. numclassify-0.2.1/examples/find_perfect_numbers.py +9 -0
  7. numclassify-0.2.1/examples/random_classify.py +6 -0
  8. numclassify-0.2.1/examples/stream_large_range.py +7 -0
  9. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/__init__.py +42 -33
  10. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_registry.py +3 -0
  11. {numclassify-0.2.0 → numclassify-0.2.1}/pyproject.toml +6 -6
  12. numclassify-0.2.0/site/404.html +0 -490
  13. numclassify-0.2.0/site/api/index.html +0 -731
  14. numclassify-0.2.0/site/assets/images/favicon.png +0 -0
  15. numclassify-0.2.0/site/assets/javascripts/bundle.79ae519e.min.js +0 -16
  16. numclassify-0.2.0/site/assets/javascripts/bundle.79ae519e.min.js.map +0 -7
  17. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ar.min.js +0 -1
  18. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.da.min.js +0 -18
  19. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.de.min.js +0 -18
  20. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.du.min.js +0 -18
  21. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.el.min.js +0 -1
  22. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.es.min.js +0 -18
  23. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.fi.min.js +0 -18
  24. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.fr.min.js +0 -18
  25. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.he.min.js +0 -1
  26. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.hi.min.js +0 -1
  27. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.hu.min.js +0 -18
  28. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.hy.min.js +0 -1
  29. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.it.min.js +0 -18
  30. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ja.min.js +0 -1
  31. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.jp.min.js +0 -1
  32. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.kn.min.js +0 -1
  33. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ko.min.js +0 -1
  34. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.multi.min.js +0 -1
  35. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.nl.min.js +0 -18
  36. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.no.min.js +0 -18
  37. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.pt.min.js +0 -18
  38. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ro.min.js +0 -18
  39. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ru.min.js +0 -18
  40. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.sa.min.js +0 -1
  41. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +0 -1
  42. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.sv.min.js +0 -18
  43. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.ta.min.js +0 -1
  44. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.te.min.js +0 -1
  45. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.th.min.js +0 -1
  46. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.tr.min.js +0 -18
  47. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.vi.min.js +0 -1
  48. numclassify-0.2.0/site/assets/javascripts/lunr/min/lunr.zh.min.js +0 -1
  49. numclassify-0.2.0/site/assets/javascripts/lunr/tinyseg.js +0 -206
  50. numclassify-0.2.0/site/assets/javascripts/lunr/wordcut.js +0 -6708
  51. numclassify-0.2.0/site/assets/javascripts/workers/search.2c215733.min.js +0 -42
  52. numclassify-0.2.0/site/assets/javascripts/workers/search.2c215733.min.js.map +0 -7
  53. numclassify-0.2.0/site/assets/stylesheets/main.484c7ddc.min.css +0 -1
  54. numclassify-0.2.0/site/assets/stylesheets/main.484c7ddc.min.css.map +0 -1
  55. numclassify-0.2.0/site/assets/stylesheets/palette.ab4e12ef.min.css +0 -1
  56. numclassify-0.2.0/site/assets/stylesheets/palette.ab4e12ef.min.css.map +0 -1
  57. numclassify-0.2.0/site/changelog/index.html +0 -533
  58. numclassify-0.2.0/site/cli/index.html +0 -732
  59. numclassify-0.2.0/site/index.html +0 -661
  60. numclassify-0.2.0/site/search/search_index.json +0 -1
  61. numclassify-0.2.0/site/sitemap.xml +0 -19
  62. numclassify-0.2.0/site/sitemap.xml.gz +0 -0
  63. {numclassify-0.2.0 → numclassify-0.2.1}/.github/workflows/ci.yml +0 -0
  64. {numclassify-0.2.0 → numclassify-0.2.1}/.github/workflows/publish.yml +0 -0
  65. {numclassify-0.2.0 → numclassify-0.2.1}/CHANGELOG.md +0 -0
  66. {numclassify-0.2.0 → numclassify-0.2.1}/LICENSE +0 -0
  67. {numclassify-0.2.0 → numclassify-0.2.1}/README.md +0 -0
  68. {numclassify-0.2.0 → numclassify-0.2.1}/docs/api.md +0 -0
  69. {numclassify-0.2.0 → numclassify-0.2.1}/docs/changelog.md +0 -0
  70. {numclassify-0.2.0 → numclassify-0.2.1}/docs/cli.md +0 -0
  71. {numclassify-0.2.0 → numclassify-0.2.1}/docs/index.md +0 -0
  72. {numclassify-0.2.0 → numclassify-0.2.1}/mkdocs.yml +0 -0
  73. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/__main__.py +0 -0
  74. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/__init__.py +0 -0
  75. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/combinatorial.py +0 -0
  76. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/digital.py +0 -0
  77. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/divisors.py +0 -0
  78. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/figurate.py +0 -0
  79. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/number_theory.py +0 -0
  80. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/powers.py +0 -0
  81. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/primes.py +0 -0
  82. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/recreational.py +0 -0
  83. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/_core/sequences.py +0 -0
  84. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/cli.py +0 -0
  85. {numclassify-0.2.0 → numclassify-0.2.1}/numclassify/py.typed +0 -0
  86. {numclassify-0.2.0 → numclassify-0.2.1}/tests/test_registry.py +0 -0
@@ -9,3 +9,4 @@ dist/
9
9
  *.egg-info/
10
10
  .env
11
11
  .venv
12
+ site/
@@ -0,0 +1,71 @@
1
+ # Contributing to numclassify
2
+
3
+ ## Adding a New Number Type
4
+
5
+ The fastest way to contribute is adding a new number type using the `@register` decorator.
6
+
7
+ ### Step 1 \u2014 Write your function
8
+
9
+ ```python
10
+ from numclassify import register
11
+
12
+ @register(name="My Type", category="recreational")
13
+ def is_my_type(n: int) -> bool:
14
+ return n > 0 and n % 7 == 0
15
+ ```
16
+
17
+ That's it. Your type is now available via:
18
+ - `nc.get_all_properties(n)`
19
+ - `nc.get_true_properties(n)`
20
+ - `nc.find_in_range(nc.is_my_type, 1, 1000)`
21
+ - `numclassify find my_type` in the CLI
22
+
23
+ ### Step 2 \u2014 Add it to the right module
24
+
25
+ Place your function in the appropriate file under `numclassify/_core/`:
26
+
27
+ | Module | Types |
28
+ |---|---|
29
+ | `primes.py` | Prime families |
30
+ | `figurate.py` | Polygonal/figurate numbers |
31
+ | `divisors.py` | Divisor-based (perfect, abundant...) |
32
+ | `digital.py` | Digit-based (Armstrong, Harshad...) |
33
+ | `sequences.py` | Number sequences (Fibonacci, Lucas...) |
34
+ | `powers.py` | Powers and sums |
35
+ | `number_theory.py` | Number theory properties |
36
+ | `combinatorial.py` | Combinatorial numbers |
37
+ | `recreational.py` | Recreational/fun types |
38
+
39
+ ### Step 3 \u2014 Add a test
40
+
41
+ Add a test in `tests/` following the existing pattern:
42
+
43
+ ```python
44
+ def test_is_my_type():
45
+ assert nc.is_my_type(7) == True
46
+ assert nc.is_my_type(1) == False
47
+ ```
48
+
49
+ ### Step 4 \u2014 Submit a PR
50
+
51
+ ```bash
52
+ git checkout -b add-my-type
53
+ git add .
54
+ git commit -m "Add My Type number classification"
55
+ git push origin add-my-type
56
+ ```
57
+
58
+ Then open a pull request on GitHub.
59
+
60
+ ## Running Tests
61
+
62
+ ```bash
63
+ cd numclassify
64
+ python -m pytest tests/ -v
65
+ ```
66
+
67
+ ## Code Style
68
+
69
+ - Pure Python, no external dependencies
70
+ - Type hints required on all functions
71
+ - Function name must start with `is_` for boolean classifiers
@@ -1,15 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numclassify
3
- Version: 0.2.0
4
- Summary: The most comprehensive Python library for number classification 3000+ number types
3
+ Version: 0.2.1
4
+ Summary: The most comprehensive Python library for number classification - 3000+ number types
5
5
  Project-URL: Homepage, https://github.com/aratrikghosh2011-tech/numclassify
6
6
  Project-URL: Repository, https://github.com/aratrikghosh2011-tech/numclassify
7
+ Project-URL: Documentation, https://aratrikghosh2011-tech.github.io/numclassify/
7
8
  Project-URL: Issues, https://github.com/aratrikghosh2011-tech/numclassify/issues
8
9
  Author-email: Aratrik Ghosh <aratrikghosh2011@gmail.com>
9
10
  License: MIT
10
11
  License-File: LICENSE
11
12
  Keywords: armstrong,classification,figurate,mathematics,number-theory,prime
12
- Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Development Status :: 4 - Beta
13
14
  Classifier: Intended Audience :: Education
14
15
  Classifier: Intended Audience :: Science/Research
15
16
  Classifier: License :: OSI Approved :: MIT License
@@ -20,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.9
20
21
  Classifier: Programming Language :: Python :: 3.10
21
22
  Classifier: Programming Language :: Python :: 3.11
22
23
  Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
23
25
  Classifier: Topic :: Scientific/Engineering :: Mathematics
24
26
  Requires-Python: >=3.8
25
27
  Description-Content-Type: text/markdown
@@ -0,0 +1,6 @@
1
+ import numclassify as nc
2
+
3
+ print(nc.classify(1729))
4
+ print(nc.classify_batch([6, 28, 496]))
5
+ print(nc.get_true_properties(153))
6
+ print(nc.count_properties(28))
@@ -0,0 +1,12 @@
1
+ from numclassify import register
2
+ import numclassify as nc
3
+
4
+ # Add a custom number type using the @register decorator
5
+ @register(name="Lucky Seven Multiple", category="recreational")
6
+ def is_lucky_seven_multiple(n: int) -> bool:
7
+ return n > 0 and n % 7 == 0 and "7" in str(n)
8
+
9
+ # Now works across the entire API
10
+ print(nc.is_lucky_seven_multiple(77)) # True
11
+ print(nc.is_lucky_seven_multiple(14)) # False
12
+ print("Lucky Seven Multiples under 200:", nc.find_in_range(nc.is_lucky_seven_multiple, 1, 200))
@@ -0,0 +1,9 @@
1
+ import numclassify as nc
2
+
3
+ # Find all perfect numbers under 10000
4
+ perfect = nc.find_by_property(start=1, end=10000, Perfect=True)
5
+ print("Perfect numbers:", perfect)
6
+
7
+ # Find numbers that are both perfect and odious
8
+ perfect_odious = nc.find_by_property(start=1, end=10000, Perfect=True, Odious=True)
9
+ print("Perfect and Odious:", perfect_odious)
@@ -0,0 +1,6 @@
1
+ import numclassify as nc
2
+
3
+ # Classify 5 random numbers
4
+ for _ in range(5):
5
+ result = nc.random_number(max_n=100000)
6
+ print(f"{result['number']}: {result['score']} properties \u2014 {result['true_properties'][:3]}")
@@ -0,0 +1,7 @@
1
+ import numclassify as nc
2
+
3
+ # Memory-safe streaming over large range
4
+ # Print any number with score > 30
5
+ for result in nc.stream(1, 10000):
6
+ if result["score"] > 30:
7
+ print(f"{result['number']}: score={result['score']}, types={result['true_properties'][:5]}")
@@ -24,28 +24,28 @@ Public API
24
24
  find_by_property
25
25
  stream
26
26
  """
27
- from __future__ import annotations
28
27
 
29
- import random as _random
30
- from typing import Generator, Iterator, List, Dict, Optional, Any
28
+ from __future__ import annotations
29
+ del annotations
31
30
 
32
- __version__ = "0.2.0"
31
+ __version__ = "0.2.1"
33
32
 
34
33
  # --- Import all _core submodules so @register decorators fire at import time ---
35
- from numclassify._core import primes # noqa: F401
36
- from numclassify._core import figurate # noqa: F401
37
- from numclassify._core import digital # noqa: F401
38
- from numclassify._core import recreational # noqa: F401
39
- from numclassify._core import divisors # noqa: F401
40
- from numclassify._core import sequences # noqa: F401
41
- from numclassify._core import powers # noqa: F401
42
- from numclassify._core import number_theory # noqa: F401
43
- from numclassify._core import combinatorial # noqa: F401
34
+ from numclassify._core import primes as _primes # noqa: F401
35
+ from numclassify._core import figurate as _figurate # noqa: F401
36
+ from numclassify._core import digital as _digital # noqa: F401
37
+ from numclassify._core import recreational as _recreational # noqa: F401
38
+ from numclassify._core import divisors as _divisors # noqa: F401
39
+ from numclassify._core import sequences as _sequences # noqa: F401
40
+ from numclassify._core import powers as _powers # noqa: F401
41
+ from numclassify._core import number_theory as _number_theory # noqa: F401
42
+ from numclassify._core import combinatorial as _combinatorial # noqa: F401
44
43
 
45
44
  # --- Re-export key functions at top level ---
46
45
  from numclassify._core.primes import is_prime # noqa: F401
47
46
  from numclassify._core.digital import is_armstrong # noqa: F401
48
47
  from numclassify._core.divisors import is_perfect # noqa: F401
48
+ from numclassify._registry import register # noqa: F401
49
49
  from numclassify._registry import ( # noqa: F401
50
50
  get_all_properties,
51
51
  get_true_properties,
@@ -56,12 +56,25 @@ from numclassify._registry import ( # noqa: F401
56
56
  most_special_in_range,
57
57
  )
58
58
 
59
+ # ---------------------------------------------------------------------------
60
+ # Dynamic attribute fallback — allows nc.<any_registered_type>() to work
61
+ # ---------------------------------------------------------------------------
62
+
63
+ def __getattr__(name: str):
64
+ """Fallback: look up *name* in the global registry as a normalised key."""
65
+ from numclassify._registry import REGISTRY, _normalize
66
+
67
+ key = _normalize(name)
68
+ if key in REGISTRY:
69
+ return REGISTRY[key].func
70
+ raise AttributeError(f"module 'numclassify' has no attribute {name!r}")
71
+
59
72
 
60
73
  # ---------------------------------------------------------------------------
61
74
  # New features
62
75
  # ---------------------------------------------------------------------------
63
76
 
64
- def classify(n: int) -> Dict[str, Any]:
77
+ def classify(n: int) -> dict:
65
78
  """
66
79
  Returns a summary dict for a single integer.
67
80
 
@@ -74,11 +87,10 @@ def classify(n: int) -> Dict[str, Any]:
74
87
  }
75
88
  """
76
89
  raw = get_true_properties(n)
77
- # get_true_properties returns dict[str, bool] — extract just the names
78
90
  if isinstance(raw, dict):
79
91
  true_props = [k for k, v in raw.items() if v]
80
92
  else:
81
- true_props = list(raw) # already a list, keep as-is
93
+ true_props = list(raw)
82
94
 
83
95
  return {
84
96
  "number": n,
@@ -87,25 +99,20 @@ def classify(n: int) -> Dict[str, Any]:
87
99
  }
88
100
 
89
101
 
90
- def classify_batch(numbers: List[int]) -> List[Dict[str, Any]]:
91
- """
92
- Accepts a list of ints.
93
- Returns a list of classify(n) dicts, one per number, same order.
94
- """
102
+ def classify_batch(numbers: list) -> list:
103
+ """Returns a list of classify(n) dicts, one per number, same order."""
95
104
  return [classify(n) for n in numbers]
96
105
 
97
106
 
98
- def random_number(max_n: int = 10000) -> Dict[str, Any]:
99
- """
100
- Picks a random int between 1 and max_n inclusive.
101
- Returns the classify(n) result for that number.
102
- """
107
+ def random_number(max_n: int = 10000) -> dict:
108
+ """Picks a random int between 1 and max_n inclusive, returns classify(n)."""
109
+ import random as _random
103
110
  n = _random.randint(1, max_n)
104
111
  return classify(n)
105
112
 
106
113
 
107
114
  def find_by_property(start: int = 1, end: int = 1000,
108
- limit: Optional[int] = None, **filters: bool) -> List[int]:
115
+ limit: int | None = None, **filters: bool) -> list:
109
116
  """
110
117
  Query numbers by property values within [start, end].
111
118
 
@@ -116,8 +123,7 @@ def find_by_property(start: int = 1, end: int = 1000,
116
123
  limit : int, optional
117
124
  Stop after finding this many matches.
118
125
  **filters : bool
119
- Property name required bool value.
120
- Names must match keys in get_all_properties() exactly.
126
+ Property name to required bool value mapping.
121
127
 
122
128
  Returns
123
129
  -------
@@ -140,7 +146,7 @@ def find_by_property(start: int = 1, end: int = 1000,
140
146
  return results
141
147
 
142
148
 
143
- def stream(start: int, end: int) -> Generator[Dict[str, Any], None, None]:
149
+ def stream(start: int, end: int):
144
150
  """Generator. Yields classify(n) for each n in [start, end]. Memory-safe for large ranges."""
145
151
  for n in range(start, end + 1):
146
152
  yield classify(n)
@@ -152,7 +158,6 @@ def stream(start: int, end: int) -> Generator[Dict[str, Any], None, None]:
152
158
 
153
159
  __all__ = [
154
160
  "__version__",
155
- # existing
156
161
  "is_prime",
157
162
  "is_armstrong",
158
163
  "is_perfect",
@@ -163,10 +168,14 @@ __all__ = [
163
168
  "find_all_in_range",
164
169
  "count_properties",
165
170
  "most_special_in_range",
166
- # new
167
171
  "classify",
168
172
  "classify_batch",
169
173
  "random_number",
170
174
  "find_by_property",
171
175
  "stream",
172
- ]
176
+ ]
177
+
178
+ # Clean up internal names that leak into dir(nc)
179
+ del (_primes, _figurate, _digital, _recreational,
180
+ _divisors, _sequences, _powers, _number_theory,
181
+ _combinatorial, _core, _registry)
@@ -123,6 +123,9 @@ def register(
123
123
  key = _normalize(name)
124
124
  with _REGISTRY_LOCK:
125
125
  REGISTRY[key] = entry
126
+ # Also register under the function's __name__ so
127
+ # nc.<func_name>() works via __getattr__ fallback
128
+ REGISTRY[_normalize(func.__name__)] = entry
126
129
  for alias in _aliases:
127
130
  REGISTRY[_normalize(alias)] = entry
128
131
  return func
@@ -4,15 +4,15 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "numclassify"
7
- version = "0.2.0"
8
- description = "The most comprehensive Python library for number classification 3000+ number types"
7
+ version = "0.2.1"
8
+ description = "The most comprehensive Python library for number classification - 3000+ number types"
9
9
  authors = [{name = "Aratrik Ghosh", email = "aratrikghosh2011@gmail.com"}]
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.8"
12
12
  license = {text = "MIT"}
13
13
  keywords = ["number-theory", "mathematics", "classification", "armstrong", "prime", "figurate"]
14
14
  classifiers = [
15
- "Development Status :: 3 - Alpha",
15
+ "Development Status :: 4 - Beta",
16
16
  "Intended Audience :: Education",
17
17
  "Intended Audience :: Science/Research",
18
18
  "Topic :: Scientific/Engineering :: Mathematics",
@@ -22,6 +22,7 @@ classifiers = [
22
22
  "Programming Language :: Python :: 3.10",
23
23
  "Programming Language :: Python :: 3.11",
24
24
  "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
25
26
  "License :: OSI Approved :: MIT License",
26
27
  "Operating System :: OS Independent",
27
28
  ]
@@ -29,6 +30,7 @@ classifiers = [
29
30
  [project.urls]
30
31
  Homepage = "https://github.com/aratrikghosh2011-tech/numclassify"
31
32
  Repository = "https://github.com/aratrikghosh2011-tech/numclassify"
33
+ Documentation = "https://aratrikghosh2011-tech.github.io/numclassify/"
32
34
  Issues = "https://github.com/aratrikghosh2011-tech/numclassify/issues"
33
35
 
34
36
  [project.scripts]
@@ -36,6 +38,4 @@ numclassify = "numclassify.cli:main"
36
38
 
37
39
  [tool.hatch.build.targets.wheel]
38
40
  packages = ["numclassify"]
39
-
40
- [tool.setuptools.package-data]
41
- numclassify = ["py.typed"]
41
+ include = ["numclassify/py.typed"]