Compare commits

..

No commits in common. "master" and "feature/bananarama" have entirely different histories.

12 changed files with 227 additions and 284 deletions

View file

@ -1,13 +1,13 @@
=======
Credits
=======
Development Lead
================
----------------
* itec <itec@ventuordici.org>
Contributors
============
------------
* Autoscatto
* Baku
* Boyska
* Encrypt
* Thegamer
None yet. Why not be the first?

View file

@ -9,16 +9,9 @@ banana
Features
--------
- Supports multiple, super-interesting bases: banana 🍌, ananas 🍍, ribes 🍇 avocado 🥑
- Encode and decode easily
- Check validity of encoded words
- Generate random words 🎲
- It's easy to support additional bases based on the same principles 🧩
- TODO
Credits
-------
Thanks to Autoscatto, Baku, Boyska for suggestions and developement.
Special thanks to Stefano Bartezzaghi.
Loosely inspired by Stefano Bartezzaghi's book "Accavallavacca. Inventario di parole da gioco", Milano, Bompiani, 1992. ISBN 88-452-1948-8.
All hail Stefano Bartezzaghi

View file

@ -1,6 +1,5 @@
"""Top-level package for banana."""
from .libbanana import *
__author__ = """itec"""
__email__ = "itec@ventuordici.org"
__version__ = "0.1.0"
__email__ = 'itec@ventuordici.org'
__version__ = '0.1.0'

81
banana/bananalib.py Normal file
View file

@ -0,0 +1,81 @@
"""Main module."""
def dec2banana(num, dictstart=0, shiftend=0, minlength=0, dictionary=None):
if dictionary is None:
dictionary = [list("bcdfglmnprstvz"), list("aeiou")]
numdict = len(dictionary)
v = num
st = ""
length = 0
idx = (numdict - 1 + dictstart + shiftend) % numdict
while not (v == 0 and idx == (numdict - 1 + dictstart) % numdict and length >= minlength):
r = v % len(dictionary[idx])
v = int(v / len(dictionary[idx]))
st = dictionary[idx][r] + st
idx = (idx - 1) % numdict
length += 1
return st
def banana2dec(banana, dictstart=0, shiftend=0, dictionary=None):
# defaults
if dictionary is None:
dictionary = [list("bcdfglmnprstvz"), list("aeiou")] # , list("123456")
numdict = len(dictionary)
if (len(banana) - shiftend) % numdict != 0:
return "Banana non valida"
v = 0
for i in range(len(banana)):
r = (numdict + i + dictstart) % numdict
try:
v = v * len(dictionary[r]) + dictionary[r].index(banana[i])
except (ValueError, KeyError) as e:
return "Carattere non valido in posizione", i + 1
return v
def bananarandom(dictstart=0, shiftend=0, minlength=6, dictionary=None):
import random
# defaults
if dictionary is None:
dictionary = [list("bcdfglmnprstvz"), list("aeiou")]
numdict = len(dictionary)
st = ""
length = 0
i = (numdict - 1 + dictstart + shiftend) % numdict
while not (i == (numdict - 1 + dictstart) % numdict and length >= minlength):
r = random.randint(0, len(dictionary[i]) - 1)
st = dictionary[i][r] + st
i = (i - 1) % numdict
length += 1
return st
def isbanana(banana, dictstart=0, shiftend=0, dictionary=None):
# defaults
if dictionary is None:
dictionary = [list("bcdfglmnprstvz"), list("aeiou")] # , list("123456")
numdict = len(dictionary)
if (len(banana) - shiftend) % numdict != 0:
return False
for i in range(len(banana)):
r = (numdict + i + dictstart) % numdict
if banana[i] not in dictionary[r]:
return False
return True
if __name__ == "__main__":
print("Ciao sono la libreria banana")

View file

@ -1,103 +1,110 @@
"""Console script for banana."""
import argparse
import logging
import random
from . import bananalib as banana
import sys
import banana
def ananas2dec():
parser = argparse.ArgumentParser(description="Convert ananas string to dec")
parser.add_argument("ananas", help="String to be converted")
args = parser.parse_args()
print(banana.banana2dec(args.ananas, 1, 0))
def get_codec(args):
kwargs = {}
if args.alphabets:
kwargs["alphabets"] = args.alphabets
if args.shiftalpha:
kwargs["shiftalpha"] = args.shiftalpha
if args.alphaend:
kwargs["alphaend"] = args.alphaend
return banana.Codec(**kwargs)
def avocado2dec():
parser = argparse.ArgumentParser(description="Convert avocado string to dec")
parser.add_argument("avocado", help="String to be converted")
args = parser.parse_args()
print(banana.banana2dec(args.avocado, 1, 0))
def main_encode(args):
codec = get_codec(args)
kwargs = dict(num=args.num)
if args.minlength:
kwargs["minlength"] = args.minlength
print(codec.encode(**kwargs))
def banana2dec():
parser = argparse.ArgumentParser(description="Convert banana string to dec")
parser.add_argument("banana", help="String to be converted")
parser.add_argument("--dictionary", help="Set dictionary", type=list, nargs='+')
parser.add_argument("--dictstart", help="Set starting dictionary", type=int, default=0)
parser.add_argument("--shiftend", help="Set shift for ending dictionary", type=int, default=0)
args = parser.parse_args()
print(banana.banana2dec(args.banana, args.dictstart, args.shiftend, args.dictionary))
def main_decode(args):
print(get_codec(args).decode(args.word))
def ribes2dec():
parser = argparse.ArgumentParser(description="Convert ribes string to dec")
parser.add_argument("ribes", help="String to be converted")
args = parser.parse_args()
print(banana.banana2dec(args.ribes, 1, 0))
def main_check(args):
if get_codec(args).is_valid(args.word):
if not args.quiet:
print("yes")
sys.exit(0)
else:
if not args.quiet:
print("no")
sys.exit(1)
def bananarandom():
parser = argparse.ArgumentParser(description="Generate random banana")
parser.add_argument("--dictionary", help="Set dictionary", type=list, nargs='+')
parser.add_argument("--dictstart", help="Set starting dictionary", type=int, default=0)
parser.add_argument("--shiftend", help="Set shift for ending dictionary", type=int, default=0)
parser.add_argument("--minlength", help="Set minimum length", type=int, default=6)
args = parser.parse_args()
print(banana.bananarandom(args.dictstart, args.shiftend, args.minlength, args.dictionary))
def main_random(args):
codec = get_codec(args)
kwargs = dict(minlength=args.minlength)
if args.seed:
kwargs["prng"] = random.Random(args.seed)
print(codec.random(**kwargs))
def dec2ananas():
parser = argparse.ArgumentParser(description="Convert dec number to ananas")
parser.add_argument("num", help="Number to be converted", type=int)
parser.add_argument("--minlength", help="Set minimum length", type=int, default=0)
args = parser.parse_args()
print(banana.dec2banana(args.num, 1, 0, args.minlength))
def colon_separated_list(s):
return s.split(":")
def dec2avocado():
parser = argparse.ArgumentParser(description="Convert dec number to avocado")
parser.add_argument("num", help="Number to be converted", type=int)
parser.add_argument("--minlength", help="Set minimum length", type=int, default=0)
args = parser.parse_args()
print(banana.dec2banana(args.num, 1, 1, args.minlength))
def dec2banana():
parser = argparse.ArgumentParser(description="Convert dec number to banana")
parser.add_argument("num", help="Number to be converted", type=int)
parser.add_argument("--dictionary", help="Set dictionary", type=list, nargs='+')
parser.add_argument("--dictstart", help="Set starting dictionary", type=int, default=0)
parser.add_argument("--shiftend", help="Set shift for ending dictionary", type=int, default=0)
parser.add_argument("--minlength", help="Set minimum length", type=int, default=0)
args = parser.parse_args()
print(banana.dec2banana(args.num, args.dictstart, args.shiftend, args.minlength, args.dictionary))
def dec2ribes():
parser = argparse.ArgumentParser(description="Convert dec number to ribes")
parser.add_argument("num", help="Number to be converted", type=int)
parser.add_argument("--minlength", help="Set minimum length", type=int, default=0)
args = parser.parse_args()
print(banana.dec2banana(args.num, 1, 1, args.minlength))
def isbanana():
parser = argparse.ArgumentParser(description="Checks if string is banana")
parser.add_argument("banana", help="String to be checked")
parser.add_argument("--dictionary", help="Set dictionary", type=list, nargs='+')
parser.add_argument("--dictstart", help="Set starting dictionary", type=int, default=0)
parser.add_argument("--shiftend", help="Set shift for ending dictionary", type=int, default=0)
args = parser.parse_args()
print(banana.isbanana(args.banana, args.dictstart, args.shiftend, args.dictionary))
def main():
parser = argparse.ArgumentParser(description="Convert number to banana")
parser.add_argument(
"--log-level", choices=["DEBUG", "INFO", "WARN", "ERROR"], default="WARN"
)
parser.add_argument(
"--alphabets", "-a",
help="Set alphabets in colon-separated list",
type=colon_separated_list,
)
parser.add_argument(
"--shiftalpha", "-s", help="Set shift for alphabets", type=int, default=0
)
parser.add_argument(
"--alphaend", "-e", help="Set ending alphabet", type=int, default=0
)
sub = parser.add_subparsers()
encode = sub.add_parser("encode", help="Convert number to word")
encode.add_argument("num", type=int)
encode.add_argument("--minlength", "-l", help="Set minimum length", type=int, default=1)
encode.set_defaults(func=main_encode)
decode = sub.add_parser("decode", help="Convert word to number")
decode.add_argument("word")
decode.set_defaults(func=main_decode)
check = sub.add_parser("check", help="Check if word is banana")
check.add_argument("word")
check.add_argument("--quiet", "-q", action="store_true")
check.set_defaults(func=main_check)
rand = sub.add_parser("random", help="Generate random banana")
rand.add_argument("--minlength", "-l", help="Set minimum length", type=int, default=6)
rand.add_argument("--seed", type=int, default=None)
rand.set_defaults(func=main_random)
args = parser.parse_args()
if not hasattr(args, "func"):
print("You need to select one subcommand. \nUse --help", file=sys.stderr)
# parser.print_help()
sys.exit(1)
logging.basicConfig(level=args.log_level)
args.func(args)
sys.exit(bananarandom())
if __name__ == "__main__":
# pragma: no cover
main()

View file

@ -1,89 +0,0 @@
"""Main module."""
import logging
import random
log = logging.getLogger("libbanana")
class Codec:
def __init__(self, shiftalpha=0, alphaend=0, minlength=0, alphabets=None):
self.shiftalpha = shiftalpha
self.alphaend = alphaend
if alphabets is None:
self.alphabets = [list("bcdfglmnprstvz"), list("aeiou")]
else:
self.alphabets = alphabets
def encode(self, num, minlength=1):
alphabets = self.alphabets
numalpha = len(alphabets)
v = num
st = ""
length = 0
idx = (numalpha - 1 + self.shiftalpha + self.alphaend) % numalpha
while not (
v == 0
and idx == (numalpha - 1 + self.shiftalpha) % numalpha
and length >= minlength
):
r = v % len(alphabets[idx])
v = int(v / len(alphabets[idx]))
st = alphabets[idx][r] + st
idx = (idx + numalpha - 1) % numalpha
length += 1
return st
def decode(self, word):
alphabets = self.alphabets
numalpha = len(alphabets)
if (len(word) - self.alphaend) % numalpha != 0:
raise ValueError("Invalid banana")
v = 0
for i in range(len(word)):
r = (numalpha + i + self.shiftalpha) % numalpha
try:
v = v * len(alphabets[r]) + alphabets[r].index(word[i])
except (ValueError, KeyError):
raise ValueError("Invalid character in position %d" % i + 1)
return v
def is_valid(self, word):
alphabets = self.alphabets
numalpha = len(alphabets)
if (len(word) - self.alphaend) % numalpha != 0:
return False
for i in range(len(word)):
r = (numalpha + i + self.shiftalpha) % numalpha
if word[i] not in alphabets[r]:
return False
return True
def random(self, minlength=6, prng=random.Random()):
numalpha = len(self.alphabets)
word = ""
if minlength < 1:
return ""
curr_alpha = (numalpha - 1 + self.shiftalpha + self.alphaend) % numalpha
final_alpha = (numalpha - 1 + self.shiftalpha) % numalpha
while curr_alpha != final_alpha or len(word) < minlength:
word = prng.choice(self.alphabets[curr_alpha]) + word
curr_alpha = (curr_alpha - 1) % numalpha
return word
class BananaCodec(Codec):
def __init__(self):
super().__init__()
if __name__ == "__main__":
print("Hi I'm the basebanana library")

View file

@ -31,12 +31,7 @@ import banana
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"m2r",
"sphinxemoji.sphinxemoji",
]
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'm2r']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View file

@ -1,15 +1,13 @@
pip==23.2.1
pip==19.2.3
bump2version==0.5.11
wheel==0.33.6
watchdog==0.9.0
flake8==3.7.8
tox==4.11.3
tox==3.14.0
coverage==4.5.4
Sphinx==1.8.5
m2r==0.2.1
twine==1.14.0
sphinxemoji==0.1.7
pytest==6.2.5
pytest==4.6.5
pytest-runner==5.1

View file

@ -22,4 +22,5 @@ exclude = docs
test = pytest
[tool:pytest]
addopts = --ignore=setup.py
collect_ignore = ['setup.py']

View file

@ -2,53 +2,64 @@
"""The setup script."""
from setuptools import find_packages, setup
from setuptools import setup, find_packages
with open("README.md") as readme_file:
with open('README.rst') as readme_file:
readme = readme_file.read()
with open("HISTORY.rst") as history_file:
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = []
requirements = [
setup_requirements = ["pytest-runner"]
]
test_requirements = ["pytest>=3"]
setup_requirements = ['pytest-runner', ]
test_requirements = ['pytest>=3', ]
setup(
author="itec",
author_email="itec@ventuordici.org",
python_requires=">=3.5",
author_email='itec@ventuordici.org',
python_requires='>=3.5',
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
description="basebanana",
description="banana",
entry_points={
"console_scripts": [
"basebanana=banana.cli:main",
"banana=banana.cli:main",
]
'console_scripts': [
'banana=banana.cli:main',
'ananas2dec=banana.cli:ananas2dec',
'avocado2dec=banana.cli:avocado2dec',
'banana2dec=banana.cli:banana2dec',
'ribes2dec=banana.cli:ribes2dec',
'bananarandom=banana.cli:bananarandom',
'dec2ananas=banana.cli:dec2ananas',
'dec2avocado=banana.cli:dec2avocado',
'dec2banana=banana.cli:dec2banana',
'dec2ribes=banana.cli:dec2ribes',
'isbanana=banana.cli:isbanana'
],
},
install_requires=requirements,
license="MIT license",
long_description=readme + "\n\n" + history,
long_description=readme + '\n\n' + history,
include_package_data=True,
keywords="basebanana",
name="basebanana",
packages=find_packages(include=["banana", "banana.*"]),
keywords='banana',
name='banana',
packages=find_packages(include=['banana', 'banana.*']),
setup_requires=setup_requirements,
test_suite="tests",
test_suite='tests',
tests_require=test_requirements,
url="https://git.lattuga.net/itec/banana",
version="0.2.0",
url='https://git.lattuga.net/itec/banana',
version='0.1.0',
zip_safe=False,
)

View file

@ -1,64 +1,14 @@
#!/usr/bin/env python
"""Tests for `banana` package."""
import random
import pytest
from banana import BananaCodec
banana_conversions = {
"be": 1,
"da": 10,
"bema" : 100,
"duga": 1000,
"bibiva": 10000,
"galopa": 100000,
"bivucasa": 1000000,
"beba": 70,
"zu": 69,
"bezu": 139,
"nana": 2485,
}
@pytest.fixture(params=banana_conversions.items())
def banana_known(request):
yield request.param
banana_codec = BananaCodec()
def test_banana_to_dec_known(banana_known):
word, value = banana_known
assert banana_codec.decode(word) == value
def test_dec_to_banana_known(banana_known):
word, value = banana_known
assert banana_codec.encode(value) == word
def test_banana_is_banana(banana_known):
assert banana_codec.is_valid(banana_known[0])
def test_banana2dec_prefix_ba(banana_known):
"""un ba all'inizio non cambia nulla!"""
word, value = banana_known
for prefix in ("ba", "baba", "bababa"):
assert banana_codec.decode(prefix + word) == value
from banana import bananalib
def test_answer_to_life_the_universe_and_everything():
banana = banana_codec.decode("banana")
banana = bananalib.banana2dec("banana")
assert banana != 42
assert banana == 2485
def test_random_len_0():
assert banana_codec.random(minlength=0) == ""

View file

@ -1,11 +1,8 @@
[tox]
envlist = py35, py36, py37, py38, py39, py310, py311, flake8
envlist = py35, py36, py37, py38, flake8
[travis]
python =
3.11: py311
3.10: py310
3.9: py39
3.8: py38
3.7: py37
3.6: py36