
Security News
Bun 1.2.19 Adds Isolated Installs for Better Monorepo Support
Bun 1.2.19 introduces isolated installs for smoother monorepo workflows, along with performance boosts, new tooling, and key compatibility fixes.
This is a repo try to copy https://github.com/ramda/ramda in python.
For whom wants to use this package.
> pip install python-ramda
> pip install python-ramda -U # get the latest
>>> from ramda import curry
>>> def sum(a, b, c): return a + b + c
>>> curry(sum)(1)(2, 3)
6
>>> import ramda as R # similar to ramda syntax
>>> def sum(a, b, c): return a + b + c
>>> R.curry(sum)(1)(2, 3)
6
Because the usage of python_ramda
is almostly same to ramda
,
so we don't create any extra doc.
If you feel any behaviour is different from what is should be in ramda
,
please check below CheckList
for more details.
For whom wants to contribute to this repo.
$ pip install -U pylint
# see: https://pre-commit.com/ for more details
$ pre-commit install # please install hooks first
Checkout new branch from main
branch directly and create PR.
Functions supported now.
# different from ramda
R.add(None, None) # float('nan)
R.add(date(1,2,3), date(1,2,3)) # float('nan)
and
is a keyword in python)Currently, we only support list and dict type.
Currently, we only support list and dict type.
we are simply using python copy
module
So with no specific reason, we suggest you to use python origin copy
module as your first choice.
class Obj:
def __init__(self, x):
self.value = x
obj = Obj(42)
clone = R.clone(obj)
obj == clone # False, obj and clone have different references
isinstance(clone, Obj) # True
class Obj:
def __init__(self, x):
self.value = x
def __eq__(self, other):
return self.value == other.value
obj = Obj(42)
clone = R.clone(obj)
obj == clone # True, if Obj override __eq__ function
isinstance(clone, Obj) # True
Please notice the number of given arguments should match functions. Otherwise Python will complain about the mis-matching arguments.
For example:
fn = R.cond([
[lambda a: a == 1, lambda a: f'a == {a}'],
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])
fn(1) # a == 1
fn(2, 2) # 2 == 2
fn(2) # Throw error, because b is not provided for prediction, failed when (lambda a, b: a == b)(2), missing argument b
# to solve above issue, you should try your best to provide enough arguments
fn(1, 2) # Throw error, because (lambda(a: f'a == {a}'))(1, 2) has extra arguments 2
# To solve above issue, always use sencond function with enough arguments
# Try create cond like below.
fn = R.cond([
[lambda a: a == 1, lambda a, _: f'a == {a}'], # ignore b
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])
fn = R.cond([
[lambda a: a == 1, lambda a, *args: f'a == {a}'], # ignore any arguments
[lambda a, b: a == b, lambda a, b: f'{a} == {b}']
])
# We don't support empty object in python
class Obj:
def __init__(self, value):
self.value = value
o = Obj(42)
o == R.empty(o) # True, we will return the original cloned object
What we support for now:
# works for both dict and object
class Obj:
def __init__(self, v):
self.v = v
obj1 = Obj(1)
obj2 = Obj(1)
R.eqProps('v', obj1, obj2) # True
R.eqProps('v', {'v': 1}, {'v': 1}) # True
R.equals(float('nan'), float('nan')) # True
Similar to hasPath
.
works for both dict and object
class Obj:
def __init__(self, v):
self.v = v
obj1 = Obj(1)
R.hasIn('v', obj1) # True
R.hasIn('v', {'v': 1}) # True
R.hasPath(['a', 'b'], {'a': {'b': 42}}) # True
class Obj:
def __init__(self, v):
self.v = v
obj = Obj(1)
R.hasPath(['v'], obj) # True
R.hasPath(['v', 'child'], obj) # False
R.hasPath(['v'], {'v': 1}) # True
R.hasPath(['v', 'child'], {'v': 1}) # False
# Does not include static variable
class Obj:
v = 1
obj = Obj()
R.hasPath(['v'], obj) # False
# Also support inherited variable
class Parent:
def __init__(self, a):
self.a = a
class Child(Parent):
def __init__(self, a,b):
super().__init__(a)
self.b = b
child = Child(1, 2)
R.hasPath(['a'], child) # True
R.hasPath(['b'], child) # True
is
is a keyword in python)This is a language specific feature. So we check all python built-in types as many as we can.
R.Is(int, 1) # True
R.Is(float, 1.0) # True
R.Is(str, '1') # True
R.Is(list, [1,2,3]) # True
R.Is(dict, {'a': 1}) # True
R.Is(set, {1,2,3}) # True
R.Is(tuple, (1,2,3)) # True
R.Is(None, None) # True
R.Is(bool, True) # True
R.Is(bool, False) # True
# For user-defined object
class Parent:
pass
class Child(Parent):
pass
R.Is(Parent, Parent()) # True
R.Is(Parent, Child()) # True
R.Is(Child, Child()) # True
R.Is(Child, Parent()) # False
class Obj:
pass
# Any custom object will be treated as non-empty
R.isEmpty(Obj()) # False
R.isEmpty(None) # False
We keep the same method name as ramda, this is for checking if the given value is None or not.
For object, keys
does not return object's methods.
# When using R.keys(obj) and obj is a class instance, we use obj.__dict__ as keys.
class A:
c = 'not included'
def __init__(self):
self.a = 1
self.b = 2
a = A()
R.keys(a) # ['a', 'b']
# keys include super class attributes
class A:
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super().__init__(a)
self.b = b
class C(A):
def __init__(self, c):
self.c = c
a = A(1)
b = B(2, 3)
c = C(4)
R.keys(a) # ['a']
R.keys(b) # ['a', 'b']
R.keys(c) # ['c'], because c does not call super().__init__()
# For normal dict
R.keys({'a': 1, 'b': 2}) # ['a', 'b']
For object, keysIn
does not return object's methods.
Different from keys
, keysIn
will return all attributes of the object, including super class attributes and class static variables.
class A:
a_static = 1
def __init__(self):
self.a = 1
class B(A):
b_static = 2
def __init__(self, b):
super().__init__()
self.b = b
R.keysIn(A()) # ['a_static', 'a']
R.keysIn(B(2)) # ['a_static', 'a', 'b_static', 'b']
# For normal dict
R.keysIn({'a': 1, 'b': 2}) # ['a', 'b']
The behavior of length
is different from ramda
.
# Array
R.length([1, 2, 3]) # 3
# String
R.length('abc') # 3
# Dict
R.length({'a': 1, 'b': 2}) # 2
# Set
R.length({1, 2, 3}) # 3
# Tuple
R.length((1, 2, 3)) # 3
# Notice: Also works for any other iterable object
# Some special cases
# object with length() method
class Obj:
def length(self):
return 3
obj = Obj()
R.length(obj) # 3
# dict with length property
R.length({'a': 1, 'length': 99}) # 99, R.length will use length property instead
# return function arguments length
def f(a, b, c):
return a + b + c
R.length(f) # 3
# Any failed cases, return nan instead
R.length(None) # float('nan')
R.length(1) # float('nan')
class ObjWithoutLength:
pass
R.length(ObjWithoutLength()) # float('nan')
max
is a keyword in python)If R.Max(a, b)
a
and b
are with different types,
we will compare with str(a) and str(b).
R.Max('A', None) # None, 'A' < 'None'
min
is a keyword in python)If R.Min(a, b)
a
and b
are with different types,
we will compare with str(a) and str(b).
R.Min('A', None) # 'A', 'A' < 'None'
Python modulo on negative numbers has different behavior than JS.
5 % -3 # -1
5 % -3; // 2
we support both dict
type and object
type.
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj = Obj(1, 2)
R.omit(['v1'], obj) # {'v2': 2}
R.omit(['v1', 'v3'], obj) # {'v2': 2}
both pick
and pickAll
support both dict
and object
type.
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj = Obj(1, 2)
R.pick(['v1'], obj) # {'v1': 1}
R.pickAll(['v1', 'v3'], obj) # {'v1': 1, 'v3': None}
# works for both dict and object
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj1 = Obj(1, 2)
obj2 = Obj(3, 4)
R.pluck('v1', [obj1, obj2]) # [1, 3]
# works for both dict and object
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj1 = Obj(1, 2)
obj2 = Obj(3, 4)
R.project(['v1'], [obj1, obj2]) # [{'v1': 1}, {'v1': 3}]
# works for both dict and object
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj1 = Obj(1, 2)
R.propEq(1, 'v1', obj1) # True
R.propEq(2, 'v2', obj1) # True
R.propEq(1, 'v2', obj1) # False
R.propEq(1, 'v1', {'v1': 1}) # True
R.slice(1, 3, ['a', 'b', 'c', 'd']) # ['b', 'c']
R.slice(1, None, ['a', 'b', 'c', 'd']) # ['b', 'c', 'd']
# different from ramda
R.subtract(None, None) # float('nan)
R.subtract(date(1,2,3), date(1,2,3)) # float('nan)
R.toPairs({'a': 1, 'b': 2}) # [['a', 1], ['b', 2]]
class A:
v1 = 'not included'
def __init__(self, v2):
self.v2 = v2
R.toPairs(A(1)) # [['v2', 1]]
class B(A):
v3 = 'not included'
def __init__(self, v2, v4):
super().__init__(v2) # this is required
self.v4 = v4
b = B('v2', 'v4')
R.toPairs(b) # [['v2', 'v2'], ['v4', 'v4']]
R.toPairsIn({'a': 1, 'b': 2}) # [['a', 1], ['b', 2]]
class A:
v1 = 'included'
def __init__(self, v2):
self.v2 = v2
R.toPairsIn(A('v2')) # [['v1', 'included'], ['v2', 'v2']]
class B(A):
v3 = 'included too'
def __init__(self, v2, v4):
super().__init__(v2) # this is required
self.v4 = v4
R.toPairsIn(B('v2', 'v4')) # [['v3', 'included too'], ['v1', 'included'], ['v2', 'v2'], ['v4', 'v4']]
Partially supported
# works for both dict and object
class Obj:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
obj = Obj(1, 2)
R.values(obj) # [1, 2]
R.values({'a': 1, 'b': 2}) # [1, 2]
Use R.keysIn
to get the keys of an object.
spec(first param) is prefer to be a dict.
method where
supports both dict and object as second param.
class Obj:
def __init__(self, x, y):
self.x = x
self.y = y
spec = {'x': R.equals(1)}
R.where(spec, {'x': 1, 'y': 2}) # True
R.where(spec, Obj(1, 2)) # True
It will return a dict.
FAQs
A small clone of ramda
We found that python-ramda demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Bun 1.2.19 introduces isolated installs for smoother monorepo workflows, along with performance boosts, new tooling, and key compatibility fixes.
Security News
Popular npm packages like eslint-config-prettier were compromised after a phishing attack stole a maintainer’s token, spreading malicious updates.
Security News
/Research
A phishing attack targeted developers using a typosquatted npm domain (npnjs.com) to steal credentials via fake login pages - watch out for similar scams.