Skip to content

Commit

Permalink
Added Support for python 3.8 (#4)
Browse files Browse the repository at this point in the history
- Fixed Typing Hints
  • Loading branch information
d33p0st authored Sep 25, 2024
1 parent 2b23352 commit b79ce9c
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 24 deletions.
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ build-backend = "maturin"

[project]
name = "modstore"
version = "0.1.2"
version = "0.1.3"
description = "Basic and Moded data structures with rust backend for speed."
requires-python = ">=3.8"
dependencies = ["maturin"]
readme = {file = "README_for_PYPI.md", content-type = "text/markdown"}
license = { file = "LICENSE" }
Expand All @@ -19,6 +20,7 @@ classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand All @@ -27,11 +29,12 @@ classifiers = [
"Operating System :: OS Independent",
]


[tool.maturin]
python-source = "pysrc"
module-name = "modstore._binaries"
include = ["pysrc/**/*.pyi"]

[project.urls]
GitHub = "https://github.com/d33p0st/modstore"
GitHub = "https://github.com/d33p0st/modstore"
Pull-Requests = "https://github.com/d33p0st/modstore/pulls"
Issues = "https://github.com/d33p0st/modstore/pulls"
12 changes: 6 additions & 6 deletions pysrc/modstore/_binaries.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Precautions are needed for usage.
If not a developer, do not use this.
"""

from typing import Literal, Union, Pattern
from typing import Literal, Union, Pattern, List, Tuple

class Block:
"""# `Not to be called.`"""
Expand Down Expand Up @@ -103,11 +103,11 @@ class DAG:
"""`Returns String Representation of the DAG`"""
...

def list_nodes(self) -> list[str]:
def list_nodes(self) -> List[str]:
"""`Returns a list of all nodes that are added.`"""
...

def list_edges(self) -> list[tuple[str, str]]:
def list_edges(self) -> List[Tuple[str, str]]:
"""`Returns a list of tuple(str, str) representing edges.`"""
...

Expand All @@ -121,7 +121,7 @@ class Transaction:
"""`Returns the Transaction id.`"""
...

def get_parents(self) -> list[str]:
def get_parents(self) -> List[str]:
"""`Returns a list[str] containing the parents.`"""
...

Expand All @@ -131,7 +131,7 @@ class DAGChain:
"""`Create a Dag Chain`"""
...

def add_transaction(self, data: Union[str, bytes], parents: list[str]) -> str:
def add_transaction(self, data: Union[str, bytes], parents: List[str]) -> str:
"""`Add a transaction to the Dag Chain.`
Returns the id of the transaction.
Expand All @@ -145,7 +145,7 @@ class DAGChain:
"""
...

def get_transactions(self) -> list[str]:
def get_transactions(self) -> List[str]:
"""`Returns a list of keys (ids) of all available transactions`"""
...

Expand Down
Empty file added pysrc/modstore/python/dict.py
Empty file.
6 changes: 3 additions & 3 deletions pysrc/modstore/python/list.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Type, Union, Any, Literal, Callable, TypeVar, Generic
from typing import Type, Union, Any, Literal, Callable, TypeVar, Generic, List as basicList, Tuple
from itertools import chain, combinations
from collections import Counter, defaultdict

Expand All @@ -18,7 +18,7 @@ def __repr__(self) -> str:
"""`Return repr(self)`"""
return super().__repr__()

def __init__(self, create_from: Union[list[Any], 'List'] = []) -> None:
def __init__(self, create_from: Union[basicList[Any], 'List'] = []) -> None:
"""`Create a Modded list or List in general`
### Params
Expand Down Expand Up @@ -255,7 +255,7 @@ def swap(self, i: int, j: int):
"""
self[i], self[j] = self[j], self[i]

def partition(self, predicate: Callable) -> tuple['List', 'List']:
def partition(self, predicate: Callable) -> Tuple['List', 'List']:
"""`Partition the List based on some function.`
### Params
Expand Down
196 changes: 192 additions & 4 deletions pysrc/modstore/python/stack.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Union, Any, Iterable
from typing import Union, Any, Iterable, List as basicList
from ..exceptions.python import StackOverFlow, StackUnderFlow, StackError

class Stack(list):
def __init__(self, create_from: Union[list[Any], Iterable] = [], capacity: Union[int, None] = None) -> None:
def __init__(self, create_from: Union[basicList[Any], Iterable] = [], capacity: Union[int, None] = None) -> None:
for value in create_from:
super().append(value)

Expand All @@ -17,6 +17,9 @@ def __getitem__(self, index):
def __delitem__(self, index):
raise StackError("Stack does not support deletion via [].")

def append(self, object: Any) -> None:
raise StackError("Use Push. Append is disabled.")

@property
def top(self) -> int:
return super().__len__() - 1
Expand All @@ -29,7 +32,7 @@ def pop(self) -> Any:
Raises StackUnderFlow Exception if Stack is Empty
"""
try:
value = super().pop(-1)
value = super().pop()
except IndexError:
raise StackUnderFlow("Stack is empty.")

Expand Down Expand Up @@ -60,4 +63,189 @@ def size(self) -> int:

@property
def capacity(self) -> Union[float, int]:
return self._capacity if self._capacity is not None else float('inf')
return self._capacity if self._capacity is not None else float('inf')

@property
def sum(self) -> Union[int, float]:
"""`Returns the sum of all elements in the stack`
Raises StackError if the elements are not int or float.
"""
sum = 0
for x in self:
if not isinstance(x, int) and not isinstance(x, float):
raise StackError(f"Cannot sum Stack elements. Element type found: {type(x)}")
else:
sum += x
return sum

@property
def convertTolist(self) -> basicList[Any]:
"""`Returns a simple list of all elements in the stack`"""
stacklist = []
for x in self:
stacklist.append(x)
return stacklist

def joinWith(self, sep: str) -> str:
"""`Returns the elements of the stack as a string separated by a given separator.`
### Params
- `sep`: separator that will be in between the elements of the stack.
`NOTE`: if the element is not str, it will be forcefully typecasted.
"""
stacklist = self.convertTolist
if not isinstance(stacklist[0], str):
string = str(stacklist[0])
else:
string = stacklist[0]

for x in stacklist[1:]:
if isinstance(x, str):
string += sep + x
else:
string += sep + str(x)

return string

@staticmethod
def infixToPostfix(expression: str) -> str:
stack = Stack()
result = []

for char in expression:
if is_operand(char):
result.append(char)
elif char == '(':
stack.push(char)
elif char == ')':
while not stack.isEmpty and stack.peek != '(':
result.append(stack.pop)
stack.pop # pop '('
elif char == ' ':
continue
else:
while (not stack.isEmpty and operator_precedence(stack.peek) > operator_precedence(char)) or (not stack.isEmpty and operator_precedence(stack.peek) == operator_precedence(char) and is_left_associative(stack.peek)):
result.append(stack.pop)
stack.push(char)

while not stack.isEmpty:
result.append(stack.pop)

return ''.join(result)

@staticmethod
def infixToPrefix(expression: str) -> str:
# Reverse the infix expression and change '(' to ')' and vice versa
expression = expression[::-1]
expression = expression.replace('(', '#')
expression = expression.replace(')', '(')
expression = expression.replace('#', ')')

# Convert reversed infix to postfix
postfix = Stack.infixToPostfix(expression)

# Reverse postfix to get the prefix expression
return postfix[::-1]

@staticmethod
def postfixToInfix(expression: str) -> str:
stack = Stack()
for char in expression:
if is_operand(char):
stack.push(char)
elif char == ' ':
continue
else:
operand2 = stack.pop
operand1 = stack.pop
stack.push(f'({operand1}{char}{operand2})')
return stack.joinWith('')

@staticmethod
def prefixToInfix(expression: str) -> str:
stack = Stack()
for char in expression[::-1]:
if not is_operator(char):
stack.push(char)
elif char == ' ':
continue
else:
operand1 = stack.pop
operand2 = stack.pop
stack.push(f'({operand1}{char}{operand2})')
return stack.pop

@staticmethod
def postfixToPrefix(expression: str) -> str:
infix = Stack.postfixToInfix(expression)
return Stack.infixToPrefix(infix)

@staticmethod
def prefixToPostfix(expression: str) -> str:
infix = Stack.prefixToInfix(expression)
return Stack.infixToPostfix(infix)

ROMAN_VALUES = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
ROMAN_PAIRS = [
('M', 1000), ('CM', 900), ('D', 500), ('CD', 400),
('C', 100), ('XC', 90), ('L', 50), ('XL', 40),
('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)
]

@staticmethod
def resolveRomanNumber(number_expression: str) -> int:
roman = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}

stack = Stack()

for numeral in number_expression:
value = roman[numeral]

if not stack.isEmpty and value > stack.peek:
last = stack.pop
stack.push(value - last)
else:
stack.push(value)

return stack.sum

@staticmethod
def generateRomanNumber(number: int) -> str:
roman_pairs = [
('M', 1000), ('CM', 900), ('D', 500), ('CD', 400),
('C', 100), ('XC', 90), ('L', 50), ('XL', 40),
('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)
]

stack = Stack()

for roman, val in roman_pairs:
while number >= val:
stack.push(roman)
number -= val

return stack.joinWith('')

# infix, postfix, prefix
def operator_precedence(op: str) -> int:
if op == '+' or op == '-':
return 1
if op == '*' or op == '/':
return 2
if op == '^':
return 3
return 0

def is_left_associative(op: str) -> bool:
if op == '^':
return False # '^' is right associative
return True

def is_operator(c: str) -> bool:
return c in ['+', '-', '*', '/', '^']

def is_operand(c: str) -> bool:
return c.isalpha() or c.isdigit()

14 changes: 7 additions & 7 deletions pysrc/modstore/rust/dag.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .._binaries import DAG as _dag_inner, DAGChain as _chain_inner, Transaction as _transaction_inner
from typing import Literal, Union
from typing import Literal, Union, List, Tuple

import pickle

Expand Down Expand Up @@ -54,12 +54,12 @@ def toString(self) -> str:
return self.dag.to_string()

@property
def nodes(self) -> list[str]:
def nodes(self) -> List[str]:
"""`Returns a list of added nodes.`"""
return self.dag.list_nodes()

@property
def edges(self) -> list[tuple[str, str]]:
def edges(self) -> List[Tuple[str, str]]:
"""`Returns a list of tuple[str, str] representing edges.`"""
return self.dag.list_edges()

Expand All @@ -78,7 +78,7 @@ def id(self) -> str:
return self.transaction.get_id()

@property
def parents(self) -> list[str]:
def parents(self) -> List[str]:
"""`Returns a list[str] containing the parents.`"""
return self.transaction.get_parents()

Expand All @@ -95,7 +95,7 @@ def data(self, return_original: bool = False) -> Union[str, bytes, object]:
if return_original:
try:
return DAG.BytesToObject(data)
except pickle.UnpicklingError:
except (pickle.UnpicklingError, KeyError):
return data

class TransactionBased:
Expand All @@ -104,7 +104,7 @@ def __init__(self):
"""`Create a Transaction-Based DAG`"""
self.dag = _chain_inner()

def addTransaction(self, data: Union[str, bytes, object], parents: list[str]) -> str:
def addTransaction(self, data: Union[str, bytes, object], parents: List[str]) -> str:
"""`Add a Transaction into the DAG`
`data`: data can be any str, bytes or object such as list or dict.
Expand All @@ -120,7 +120,7 @@ def valid(self) -> bool:
return self.dag.is_valid()

@property
def transactions(self) -> list[str]:
def transactions(self) -> List[str]:
"""`Returns a list of all transactions.`"""
return self.dag.get_transactions()

Expand Down
Loading

0 comments on commit b79ce9c

Please sign in to comment.