Skip to content

Commit

Permalink
Improve python interface (#21)
Browse files Browse the repository at this point in the history
- **Breaking:** Changed top level module name to `fizzbuzz`. Use `from fizzbuzz.fizzbuzzo3 import fizzbuzz`
for rust implementation or `from fizzbuzz.fizzbuzzpy import fizzbuzz` for python implementation (slower).
- Added typing and docstring hints available in IDE
  • Loading branch information
MusicalNinjaDad authored May 13, 2024
1 parent c8388dc commit c132883
Show file tree
Hide file tree
Showing 20 changed files with 126 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# FizzBuzz Changelog

## Python 2.0.0

- **Breaking:** Changed top level module name to `fizzbuzz`. Use `from fizzbuzz.fizzbuzzo3 import fizzbuzz`
for rust implementation or `from fizzbuzz.fizzbuzzpy import fizzbuzz` for python implementation (slower).

## Rust 2.1.0 & Python 1.3.0

- Process `Vec`s / `list`s with more than 300k elements in parallel
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]

members = [
"fizzbuzz",
"fizzbuzz-rust",
"fizzbuzzo3"
]

Expand Down
2 changes: 1 addition & 1 deletion __pyversion__
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.0
2.0.0
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added fizzbuzz/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions fizzbuzz/fizzbuzzo3/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ruff: noqa: PYI021
def fizzbuzz(n: int | list[int]) -> str:
"""
Compute the fizzbuzz answer for `n` using a highly efficient algorithm written in rust.
The correct fizzbuzz answer is the original number, unless divisible by 3 or 5.
For numbers divisible by 3, the correct answer is 'fizz'.
For numbers divisible by 5, the correct answer is 'buzz'.
For numbers divisible by both 3 & 5, the correct answer is 'fizzbuzz'.
**Note:** Passing a `list` of values to fizzbuzz is more efficient than making multiple calls.
Larger lists will be processed in parallel on multiple cpu cores.
Arguments:
n: either `int` the single number to fizzbuzz or `list[int]` a list of numbers to fizzbuzz.
Returns:
A string representing the fizzbuzz result. If `n` is an integer, the string contains the fizzbuzz
answer for that number. If `n` is a list of integers, the string contains the fizzbuzz answers for each number,
separated by commas and spaces (`, `).
Examples:
Using a single value:
```
>>> from fizzbuzz.fizzbuzzo3 import fizzbuzz
>>> fizzbuzz(1)
'1'
>>> fizzbuzz(5)
'buzz'
```
Using a list:
```
>>> from fizzbuzz.fizzbuzzo3 import fizzbuzz
>>> fizzbuzz([1, 5])
'1, buzz'
```
"""
71 changes: 71 additions & 0 deletions fizzbuzz/fizzbuzzo3/repl_notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
Python 3.12.3 (main, Apr 17 2024, 00:00:00) [GCC 14.0.1 20240411 (Red Hat 14.0.1-0)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import fizzbuzz.fizzbuzzo3 as fb
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'fizzbuzz.fizzbuzzo3'
>>> import fizzbuzz.fizzbuzzpy.fizzbuzzo3 as fb
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'fizzbuzz.fizzbuzzpy'
>>> import fizzbuzzpy.fizzbuzzo3 as fb
>>> fb.fizzbuzz.__doc__
>>> fb.fizzbuzz
<built-in function fizzbuzz>
>>> dict(fb.fizzbuzz)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'builtin_function_or_method' object is not iterable
>>> fb.fizzbuzz.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute '__dict__'. Did you mean: '__dir__'?
>>> fb.fizzbuzz.__dir__
<built-in method __dir__ of builtin_function_or_method object at 0x7fda6d9922f0>
>>> fb.fizzbuzz.__dir__()
['__repr__', '__hash__', '__call__', '__getattribute__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce__', '__module__', '__doc__', '__name__', '__qualname__', '__self__', '__text_signature__', '__new__', '__str__', '__setattr__', '__delattr__', '__init__', '__reduce_ex__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
>>> fb.fizzbuzz.__text_signature__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>> fb.fizzbuzz.__text_signature__
'(num)'
>>> fb._dir__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'fizzbuzzpy.fizzbuzzo3' has no attribute '_dir__'
>>> import ast
>>> dir(fb)
['__all__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fizzbuzz']
>>> type(fb.fizzbuzz)
<class 'builtin_function_or_method'>
>>> type(type(fb.fizzbuzz))
<class 'type'>
>>> type(fb.fizzbuzz) == builtin_function_or_method
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'builtin_function_or_method' is not defined
>>> type(fb.fizzbuzz) == type('builtin_function_or_method')
False
>>> type(fb.fizzbuzz) == 'builtin_function_or_method'
False
>>> isinstance(fb.fizzbuzz, builtin_function_or_method)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'builtin_function_or_method' is not defined
>>> import types.builtin_function_or_method
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'types.builtin_function_or_method'; 'types' is not a package
>>> import types
>>> isinstance(fb.fizzbuzz, types.builtin_function_or_method)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'types' has no attribute 'builtin_function_or_method'
>>> isinstance(fb.fizzbuzz, types.BuiltinFunctionType)
True
>>> import types.BuiltinFunctionType as builtin
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'types.BuiltinFunctionType'; 'types' is not a package
>>>
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion fizzbuzzo3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ crate-type = ["cdylib"] # cdylib required for python import, rlib required for

[dependencies]
pyo3 = { git = "https://github.com/MusicalNinjaDad/pyo3.git", branch = "pyo3-testing" }
fizzbuzz = { path = "../fizzbuzz" }
fizzbuzz = { path = "../fizzbuzz-rust" }

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ Issues = "https://github.com/MusicalNinjaDad/fizzbuzz/issues"
version = { file = "__pyversion__" }

[tool.setuptools.packages.find]
where = ["fizzbuzzpy"]
where = ["fizzbuzz"]

[[tool.setuptools-rust.ext-modules]]
# Private Rust extension module to be nested into the Python package
target = "fizzbuzzo3" # The last part of the name (e.g. "_lib") has to match lib.name in Cargo.toml,
# but you can add a prefix to nest it inside of a Python package.
path = "fizzbuzzo3/Cargo.toml" # Default value, can be omitted
binding = "PyO3" # Default value, can be omitted
path = "fizzbuzzo3/Cargo.toml"
binding = "PyO3"
features = ["pyo3/extension-module"]

[tool.cibuildwheel]
Expand Down Expand Up @@ -72,7 +72,8 @@ xfail_strict = true
addopts = [
"--doctest-modules",
"--doctest-mdcodeblocks",
"--doctest-glob='*.md'",
"--doctest-glob=*.md",
"--doctest-glob=*.pyi",
]

[tool.coverage.run]
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions fizzbuzzpy/tests/perftest.py → tests/perftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# ruff: noqa
import timeit

from fizzbuzzo3 import fizzbuzz as fbo3
from fizzbuzzpy import fizzbuzz as fbpy
from fizzbuzz.fizzbuzzo3 import fizzbuzz as fbo3
from fizzbuzz.fizzbuzzpy import fizzbuzz as fbpy


REPEAT = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from fizzbuzzo3 import fizzbuzz
from fizzbuzz.fizzbuzzo3 import fizzbuzz


def test_lazy():
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fizzbuzzpy import fizzbuzz
from fizzbuzz.fizzbuzzpy import fizzbuzz


def test_lazy():
Expand Down

0 comments on commit c132883

Please sign in to comment.