1
0
Fork 0
forked from itec/banana

Compare commits

..

28 commits

Author SHA1 Message Date
cf47edacd8 Merge branch 'feat/python-3.11-support' of arto/banana into master 2024-01-01 12:27:39 +01:00
aartoni
b51d652203
Support for Python 3.11 (current stable) 2023-09-09 23:10:30 +02:00
ce4d52ba4a Contributors 2020-12-26 00:48:50 +01:00
64d29bb27c Fixed idx for compatibility 2020-12-25 23:02:07 +01:00
32d30b7b2a Changed setup + small fixes 2020-12-19 23:58:44 +01:00
e8cef5fcf3 credits 2020-10-29 17:37:25 +01:00
c8e5be7de8 args aliases in cli 2020-10-29 16:58:27 +01:00
b20719c2fa removed preset from cli 2020-10-29 16:47:13 +01:00
17d3a0167d encode minlength 2020-10-29 16:34:28 +01:00
f18d1fdc68 translated 2020-10-29 16:23:12 +01:00
989f3820a7 renamed functions 2020-10-29 16:22:30 +01:00
aec04ae2c1 Saluti 2020-10-26 21:06:51 +01:00
bacc3eb851 emoji in docs 2020-10-05 10:48:58 +02:00
68fe1102e4 aggiunge test random 2020-10-03 17:00:51 +02:00
9881d09fc5 refactor random 2020-10-03 16:26:43 +02:00
be5ebcfd5a remove useless stuff 2020-10-02 11:14:25 +02:00
bc42adea73 polishing 2020-10-02 11:13:40 +02:00
819388ca45 mega refactor con i Codec 2020-10-02 11:10:33 +02:00
5d25fd334e refactor is_valid 2020-10-02 10:46:51 +02:00
e257c5630c risistema cli 2020-10-01 20:34:40 +02:00
0d0a05e7f5 add ananas 2020-10-01 20:32:26 +02:00
dd73232769 testa meglio 2020-10-01 20:29:27 +02:00
ce80fe857d fix ribes + add avocado 2020-10-01 20:21:38 +02:00
b4ba921ed3 add ribes 2020-10-01 20:06:03 +02:00
96aa4d8153 black formatting 2020-10-01 19:53:53 +02:00
a2f23a5bfb FIX setup.py 2020-10-01 19:53:35 +02:00
20e012b782 super unit test 2020-10-01 19:53:19 +02:00
da2e09686d import più facile 2020-10-01 19:53:10 +02:00
12 changed files with 284 additions and 227 deletions

View file

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

View file

@ -9,9 +9,16 @@ banana
Features
--------
- TODO
- 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 🧩
Credits
-------
Thanks to Autoscatto, Baku, Boyska for suggestions and developement.
All hail Stefano Bartezzaghi
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.

View file

@ -1,5 +1,6 @@
"""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"

View file

@ -1,81 +0,0 @@
"""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,110 +1,103 @@
"""Console script for banana."""
import argparse
from . import bananalib as banana
import logging
import random
import sys
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))
import banana
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 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 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_encode(args):
codec = get_codec(args)
kwargs = dict(num=args.num)
if args.minlength:
kwargs["minlength"] = args.minlength
print(codec.encode(**kwargs))
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_decode(args):
print(get_codec(args).decode(args.word))
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_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 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 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 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 colon_separated_list(s):
return s.split(":")
def main():
sys.exit(bananarandom())
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)
if __name__ == "__main__":
# pragma: no cover
main()

89
banana/libbanana.py Normal file
View file

@ -0,0 +1,89 @@
"""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,7 +31,12 @@ 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']
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"m2r",
"sphinxemoji.sphinxemoji",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View file

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

View file

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

View file

@ -2,64 +2,53 @@
"""The setup script."""
from setuptools import setup, find_packages
from setuptools import find_packages, setup
with open('README.rst') as readme_file:
with open("README.md") 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"]
setup_requirements = ['pytest-runner', ]
test_requirements = ['pytest>=3', ]
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="banana",
description="basebanana",
entry_points={
'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'
],
"console_scripts": [
"basebanana=banana.cli:main",
"banana=banana.cli:main",
]
},
install_requires=requirements,
license="MIT license",
long_description=readme + '\n\n' + history,
long_description=readme + "\n\n" + history,
include_package_data=True,
keywords='banana',
name='banana',
packages=find_packages(include=['banana', 'banana.*']),
keywords="basebanana",
name="basebanana",
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.1.0',
url="https://git.lattuga.net/itec/banana",
version="0.2.0",
zip_safe=False,
)

View file

@ -1,14 +1,64 @@
#!/usr/bin/env python
"""Tests for `banana` package."""
import random
import pytest
from banana import BananaCodec
from banana import bananalib
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
def test_answer_to_life_the_universe_and_everything():
banana = bananalib.banana2dec("banana")
banana = banana_codec.decode("banana")
assert banana != 42
assert banana == 2485
def test_random_len_0():
assert banana_codec.random(minlength=0) == ""

View file

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