Skip to main content

A small clone of ramda

Project description

python_ramda

This is a repo try to copy https://github.com/ramda/ramda in python.

linting: pylint PyPI version Python Versions codecov

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
  • apply
  • applySpec
  • applyTo
  • ascend
  • assoc
  • assocPath
  • 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
  • cond
  • 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
  • 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:

  1. dict()
  2. set()
  3. list()
  4. str()
  5. any instance with empty() method
  6. 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
  • has
  • hasIn
  • hasPath
  • 0.1.2 head
  • identical
  • 0.1.2 identity
  • 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
  • 0.1.2 join
  • 0.1.4 juxt
  • 0.1.2 keys
# 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

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')
  • lens
  • lensIndex
  • lensPath
  • lensProp
  • lift
  • 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'
  • 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'
  • 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
  • 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}
  • 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
  • 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
  • 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

  1. String type, supported
  2. for others, just use str(x) instead
  • toUpper
  • transduce
  • transpose
  • traverse
  • trim
  • tryCatch
  • type
  • 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_ramda-0.4.1.tar.gz (69.1 kB view details)

Uploaded Source

Built Distribution

python_ramda-0.4.1-py3-none-any.whl (149.8 kB view details)

Uploaded Python 3

File details

Details for the file python_ramda-0.4.1.tar.gz.

File metadata

  • Download URL: python_ramda-0.4.1.tar.gz
  • Upload date:
  • Size: 69.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.5

File hashes

Hashes for python_ramda-0.4.1.tar.gz
Algorithm Hash digest
SHA256 c7ac571a5cb9ceaeb99b2f3aaba4265c0b236efb6a808eafe61198c1e25e5937
MD5 f2bfd9df1ef546dc2efd6dd042b8c1aa
BLAKE2b-256 3619f185036c0e503b6e6ca0a62ed13ae1c1d545eefbf81bbf0d74ee75dd6050

See more details on using hashes here.

File details

Details for the file python_ramda-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: python_ramda-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 149.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.5

File hashes

Hashes for python_ramda-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ca5cff8fd33763ffb7a75f4dbfe39601df76b17be75c79da69da2bdea5e871f9
MD5 f9634eb1e7d7ae7425402ff88e2a4d5b
BLAKE2b-256 0f20058ba765713ed51142705b00c2b3225604167d709f79fba5e3c04eac0b81

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page