A small clone of ramda
Project description
python_ramda
This is a repo try to copy https://github.com/ramda/ramda in python.
install
For whom wants to use this package.
> pip install python-ramda
> pip install python-ramda -U # get the latest
Usage
>>> 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
Doc
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.
Contribute
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.
CheckList
Functions supported now.
- 0.1.2 __
- 0.1.2 add
# different from ramda
R.add(None, None) # float('nan)
R.add(date(1,2,3), date(1,2,3)) # float('nan)
- addIndex
- 0.1.2 adjust
- 0.1.2 all
- Transducer part is not fully tested.
- allPass
- 0.1.2 always
- 0.1.2 And (
and
is a keyword in python) - andThen
- 0.1.2 any
- anyPass
- 0.3.0 ap
- aperture
- 0.1.2 append
- 0.7.0 apply
- applySpec
- applyTo
- ascend
- 0.8.0 assoc
Currently, we only support list and dict type.
- 0.8.0 assocPath
Currently, we only support list and dict type.
- 0.2.0 binary
- bind
- both
- call
- 0.3.0 chain
- clamp
- 0.1.2 clone
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
- collectBy
- 0.1.2 comparator
- complement
- 0.1.2 compose
- composeWith
- 0.1.2 concat
- 0.6.0 cond
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}']
])
- 0.4.0 construct
- 0.4.0 constructN
- 0.1.4 converge
- count
- 0.1.2 countBy
- 0.1.2 curry
- 0.1.2 curryN
- dec
- 0.6.0 defaultTo
- descend
- 0.1.2 difference
- 0.1.2 differenceWith
- dissoc
- dissocPath
- 0.1.2 divide
- 0.1.2 drop
- dropLast
- dropLastWhile
- dropRepeats
- dropRepeatsWith
- dropWhile
- either
- 0.1.2 empty
# 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:
- dict()
- set()
- list()
- str()
- any instance with empty() method
- any instance with 'fantasy-land/empty' property
- endsWith
- eqBy
- 0.1.2 eqProps
# 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
- 0.1.2 equals
R.equals(float('nan'), float('nan')) # True
- evolve
- 0.1.2 F
- 0.1.2 filter
- 0.1.2 find
- 0.1.4 findIndex
- 0.1.4 findLast
- 0.1.4 findLastIndex
- 0.1.2 flatten
- 0.1.2 flip
- 0.1.4 forEach
- forEachObjIndexed
- 0.3.0 fromPairs
- 0.1.2 groupBy
- groupWith
- 0.1.2 gt
- 0.1.2 gte
- 0.7.0 has
Similar to hasPath
.
- 0.7.0 hasIn
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
- hasPath Support both dict and object.
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
- 0.1.2 head
- identical
- 0.1.2 identity
- 0.8.0 ifElse
- inc
- includes
- indexBy
- 0.1.2 indexOf
- init
- innerJoin
- 0.2.2 insert
- insertAll
- 0.1.2 intersection
- intersperse
- 0.1.2 into
- invert
- invertObj
- 0.1.2 invoker
- 0.3.0 Is (
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
- 0.1.2 isEmpty
class Obj:
pass
# Any custom object will be treated as non-empty
R.isEmpty(Obj()) # False
R.isEmpty(None) # False
- isNil
We keep the same method name as ramda, this is for checking if the given value is None or not.
- 0.1.2 join
- 0.1.4 juxt
- 0.1.2 keys
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']
- 0.2.0 keysIn
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']
- 0.1.4 last
- 0.1.2 lastIndexOf
- 0.3.0 length
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')
- 0.8.0 lens
- lensIndex
- lensPath
- lensProp
- 0.7.0 lift
- 0.7.0 liftN
- 0.1.2 lt
- 0.1.2 lte
- 0.1.2 map
- mapAccum
- mapAccumRight
- mapObjIndexed
- 0.1.2 match
- 0.3.0 mathMod
- 0.1.2 Max (
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'
- 0.8.0 maxBy
- mean
- median
- memoizeWith
- mergeAll
- mergeDeepLeft
- mergeDeepRight
- mergeDeepWith
- mergeDeepWithKey
- mergeLeft
- mergeRight
- mergeWith
- mergeWithKey
- 0.1.2 Min (
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'
- 0.8.0 minBy
- modify
- modifyPath
- 0.1.4 modulo
Python modulo on negative numbers has different behavior than JS.
5 % -3 # -1
5 % -3; // 2
- move
- 0.1.2 multiply
- 0.2.0 nAry
- negate
- none
- 0.1.2 not
- 0.1.2 nth
- nthArg
- o
- 0.1.2 objOf
- 0.3.0 of
- 0.1.2 omit
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}
- on
- 0.1.2 once
- 0.1.2 or
- otherwise
- over
- pair
- partial
- partialObject
- partialRight
- 0.1.4 partition
- 0.1.2 path
- 0.7.0 pathEq
- pathOr
- 0.1.2 paths
- pathSatisfies
- 0.1.2 pick
- 0.1.2 pickAll
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}
- 0.8.0 pickBy
- 0.1.2 pipe
- pipeWith
- 0.1.2 pluck
# 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]
- 0.1.2 prepend
- 0.1.2 product
- 0.1.2 project
# 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}]
- promap
- 0.1.2 prop
- 0.1.2 propEq
# 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
- propIs
- 0.6.0 propOr
- 0.1.2 props
- propSatisfies
- 0.1.2 range
- 0.1.2 reduce
- 0.1.2 reduceBy
- 0.1.2 reduced
- 0.1.2 reduceRight
- reduceWhile
- 0.1.2 reject
- 0.2.2 remove
- 0.1.4 repeat
- 0.7.0 replace
- 0.1.2 reverse
- scan
- sequence
- set
- 0.1.2 slice
R.slice(1, 3, ['a', 'b', 'c', 'd']) # ['b', 'c']
R.slice(1, None, ['a', 'b', 'c', 'd']) # ['b', 'c', 'd']
- 0.1.2 sort
- 0.1.2 sortBy
- sortWith
- 0.1.2 split
- splitAt
- splitEvery
- splitWhen
- splitWhenever
- startsWith
- 0.1.2 subtract
# different from ramda
R.subtract(None, None) # float('nan)
R.subtract(date(1,2,3), date(1,2,3)) # float('nan)
- 0.1.2 sum
- symmetricDifference
- symmetricDifferenceWith
- 0.1.2 T
- 0.1.2 tail
- 0.1.2 take
- takeLast
- takeLastWhile
- 0.1.2 takeWhile
- 0.1.2 tap
- test
- thunkify
- 0.1.4 times
- toLower
- 0.4.0 toPairs
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']]
- 0.4.0 toPairsIn
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']]
- 0.1.2 toString
Partially supported
- String type, supported
- for others, just use str(x) instead
- toUpper
- transduce
- transpose
- traverse
- 0.6.0 trim
- tryCatch
- type
- 0.8.0 unapply
- 0.2.0 unary
- uncurryN
- unfold
- 0.1.2 union
- 0.1.2 unionWith
- 0.1.2 uniq
- 0.1.2 uniqBy
- 0.1.2 uniqWith
- unless
- 0.3.0 unnest
- until
- unwind
- update
- 0.1.2 useWith
- 0.1.2 values
# 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]
- 0.2.0 valuesIn
Use R.keysIn
to get the keys of an object.
- view
- when
- 0.1.4 where
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
- whereAny
- whereEq
- without
- xor
- 0.1.2 xprod
- 0.1.2 zip
- 0.3.0 zipObj
It will return a dict.
- 0.1.2 zipWith
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file python_ramda-0.8.0.tar.gz
.
File metadata
- Download URL: python_ramda-0.8.0.tar.gz
- Upload date:
- Size: 82.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6d4438874681b7f458d92e083822c1160a09c493a7cabc807eb4e44ae0ace861 |
|
MD5 | 026b87d796f293b2fee0a1ccff6e0dfd |
|
BLAKE2b-256 | ff2e8b056ce2465cb06413ec68c29ce0b1c95d97e90a4e4682b4dc76e9ebafb1 |
File details
Details for the file python_ramda-0.8.0-py3-none-any.whl
.
File metadata
- Download URL: python_ramda-0.8.0-py3-none-any.whl
- Upload date:
- Size: 178.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 36daf436949fe3e4e694eedc9f2a93544123d95fdd31ab6ecf1d35932eef7101 |
|
MD5 | 08f0402a2c8bc084aa3217026cfa4068 |
|
BLAKE2b-256 | c5482d1deb21a9964865ecd78f8b0d487af2146a2f2d11c40e836e37ffcd71a3 |