Giter Site home page Giter Site logo

ramda.py's Issues

The `flip` method doesn't reverse the argument's order of a partially applied function

The flip method doesn't reverse the argument's order of a partially applied function. The following example demonstrates the issue; both add and multiply are partially applied reduce. The functions are still expecting an accumulator and a list of values.
Flipping the partially applied reduce should expect a list of values and an accumulator.
Currently, this doesn't happen which results in an error TypeError: 'int' object is not iterable.

import ramda as R

# add :: Number → [Number] → Number 
add = R.reduce(lambda a, b: a + b)

# multiply :: Number → [Number] → Number 
multiply = R.reduce(lambda a, b: a * b)

total = R.compose(
    R.flip(multiply)([1, 2, 3]),
    R.flip(add)([1, 2, 3])
)(0)

assert total == 36

Using the Javascript library, it works as expected.

const assert = require('assert');
const R = require('ramda');

// add :: Number → [Number] → Number 
const add = R.reduce((a, b) => a + b);

// multiply :: Number → [Number] → Number 
const multiply = R.reduce((a, b) => a * b);

const total = R.compose(
  R.flip(multiply)([1, 2, 3]),
  R.flip(add)([1, 2, 3])
)(0);

assert.strictEqual(total, 36);

`invoker` fails when arity is 0

What I see:

The following test case

def test_open_cursor(db_context):
    class TestClass:
        def one(self):
            return 1

    one = R.invoker(0, "one")(TestClass())
    assert one == 1

fails with

arity = 0, f = 'one'

    @curry
    def invoker(arity, f):
        """Turns a named method with a specified arity into a function that can be
        called directly supplied with arguments and a target object.
        The returned function is curried and accepts arity + 1 parameters where
        the final parameter is the target object"""
        _args = ", ".join([f"x{i}" for i in range(0, arity)])
        _f = f'lambda {_args}, object: getattr(object, "{f}")({_args})'
>       return curry(eval(_f))
E         File "<string>", line 1
E           lambda , object: getattr(object, "one")()
E                  ^
E       SyntaxError: invalid syntax

What I would expect:
R.invoker(0, 'method_name')(class_instance) calls method_name on class_instance without any arguments.

times doesn't work the same as in RamdaJS

Hi,

I noticed that times doesn't work as advertised in the RamdaJS docs. The RamdaJS version runs a function n times. The Python version returns a list from 1 to n-1.

RamdaJS:

R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]

Python:

>>> from ramda import *
>>> times(identity, 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: times() takes 1 positional argument but 2 were given
>>> times(5)
[1, 2, 3, 4]

Thank you.

lt, lte, gt, gte are reversed

Hello,

It seems that lt, lte, gt, gte are reversed from their ramdajs counterparts.

In ramdajs:

R.lt(2, 1); // false
R.lte(2, 1); // false
R.gt(2, 1); // true
R.gte(2, 1); // true

In Python:

>>> lt(2,1)
True
>>> lte(2,1)
True
>>> gt(2,1)
False
>>> gte(2,1)
False

I wonder if this was an intentional decision? Because in Ramda one almost always wants to know if the second parameter is less than the first, for example. But it is inconsistent with ramdajs.

A related question: How can I use the R.__ placeholder function in Python?

R.lt(R.__, 1)(2); // false

PS. Sorry for all the issues I'm filing. I really appreciate all the great work you're doing in porting Ramda to Python!!

Feature request: R.raise

I know, this thing was an open an shut case in ramda.js (ramda/ramda#1317) and it would be much nicer to handle this kind of control flow with a Maybe type. But since no such thin exists in python afaik, how about we sidestep and implement something like this anyway?

def raise(e):
    def foo(*_):
        raise(e)
    return foo

I for sure would find it useful.

Cheers!

repeat isn't curried

Hello,

I noticed that repeat isn't curried.

RamdaJS:

R.repeat(" ")(3) // [" ", " ", " "]

Python:

>>> from ramda import *
>>> repeat(" ")(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: repeat() missing 1 required positional argument: 'times'

Thank you.

group_with(equals) should return an empty list given an empty string

Hello,

I noticed that group_with(equals) raises an exception when given an empty string.

>>> group_with(equals)('AABBB')
['AA', 'BBB']
>>> group_with(equals)('')
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    group_with(equals)('')
  File "C:\Python36\lib\site-packages\toolz\functoolz.py", line 303, in __call__
    return self._partial(*args, **kwargs)
  File "C:\Python36\lib\site-packages\ramda\group_with.py", line 11, in group_with
    group = [xs[0]]
IndexError: string index out of range

However, in ramdajs, an empty list is returned.

R.groupWith(R.equals)('AABBB') // ["AA", "BBB"]
R.groupWith(R.equals)('') // []

Thank you.

Crash in group_by

Hi, I think there is a bug in group_by: acc[key] is not initialized so you cannot append x to it. Probably acc should be a defaultdict that defaults to a list.

@curry                                                                                           
  def group_by(f, xs):                                                                      
      acc = {}                                                                                     
      for x in xs:                                                                                 
          key = f(x)                                                                               
          try:                                                                                     
              acc[key].append(x)
          except KeyError:
              acc[key] = [x]
      return acc

TypeError exception in path_or()

ramda version 0.6.0

When I try to work with none field value in source object I get such exception:
TypeError: 'NoneType' object is not subscriptable

Example source:

import ramda as R
conc={'_id': '605c5122de4f9070960f2b0e', 'deviceIndex': 0, 'concentrator': {'type': 'MK-01', 'number': '48376021016855'}, 'commissioningData': None}
print (R.path_or([], ['commissioningData', 'channelsField'], conc))

Output is
Traceback (most recent call last):
File "/home/kss/tmp/py/ramda_test.py", line 9, in
print (R.path_or([], ['commissioningData', 'channelsField'], conc))
File "/usr/lib/python3.9/site-packages/toolz/functoolz.py", line 303, in call
return self._partial(*args, **kwargs)
File "/usr/lib/python3.9/site-packages/ramda/path_or.py", line 11, in path_or
return default_to(default, _path(path, value))
File "/usr/lib/python3.9/site-packages/toolz/functoolz.py", line 303, in call
return self._partial(*args, **kwargs)
File "/usr/lib/python3.9/site-packages/ramda/path.py", line 11, in path
current_value = current_value[key]
TypeError: 'NoneType' object is not subscriptable

In JavaScript Ramda all works well

const R=require('ramda')
let conc={'_id': '605c5122de4f9070960f2b0e', 'deviceIndex': 0, 'concentrator': {'type': 'MK-01', 'number': '48376021016855'}, 'commissioningData': null}
console.log (R.pathOr([], ['commissioningData', 'channelsField'], conc))

Output is []

try_catch doesn't evaluate the catcher function

Hello,

I noticed that try_catch doesn't seem to evaluate the catcher function. For example, this is the behavior in ramdajs:

R.tryCatch(() => { throw 'foo'}, R.always('caught'))('bar') // "caught"

And here's the behavior in Python:

>>> def raise_(ex):
	raise ex

>>> try_catch(lambda: raise_(Exception('foo')), always('caught'))('bar')
<function always at 0x0000027CA97EB158>

As you can see, the catcher function is returned, not evaluated. But what's really strange is that the catcher function keeps getting returned over and over when I try to evaluate it:

>>> catcher = try_catch(lambda: raise_(Exception('foo')), always('caught'))('bar')
>>> catcher
<function always at 0x0000027CA97EC510>
>>> catcher('bar') # Expected 'caught' here
<function always at 0x0000027CA97EC378>
>>> catcher('bar')('bar') # And here
<function always at 0x0000027CA97EC1E0>

Thank you.

Error in take_last_while when last item in list fails predicate

When calling
** Expected behaviour **

xs = [(-1, '23456789')]
post = take_last_while(lambda i: i[0] == 0, xs)
assert post == []

** Current behaviour **

xs = [(-1, '23456789')]
post = take_last_while(lambda i: i[0] == 0, xs)
assert post == [(-1, '23456789')]

Types for the functions

Hi There,

Shall we add types to all these functions. Python might not be able to support all the cases we have in ramda but most of them should be possible.

What do you think?

Use collections.abc.Iterable

Python 3.7 spits this warning:

python3.7/site-packages/ramda/flatten.py:1: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working from collections import Iterable

Pipe's leftmost function should be able to accept more than one argument

Hello and thank you for porting ramdajs to Python!

I'd like to report an inconsistency between ramdajs's pipe and yours. In ramdajs, pipe's leftmost function can accept more than one argument. The documentation says: "The first argument may have any arity; the remaining arguments must be unary." For example, this works in ramdajs:

R.pipe(R.add, R.negate)(1, 2); // -3

However, in Python, the same code fails:

>>> from ramda import *
>>> pipe(add, negate)(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes 1 positional argument but 2 were given

My workaround is to wrap the leftmost function in apply. But it's not exactly the same, because you have to put the arguments into a list.

>>> pipe(apply(add), negate)([1, 2])
-3

Your compose has the same issue, but with the rightmost function.

Thank you.

Use inspect.getfullargspec()

inspect.getfullargspec() should be used instead of inspect.getargspec() to prevent DeprecationWarning in Python 3.7:

python3.7/site-packages/ramda/private/curry_spec/make_func_curry_spec.py:19: DeprecationWarning: inspect.getargspec() is deprecated since Python 3.0, use inspect.signature() or inspect.getfullargspec()

Map.py not working as expected

Hi! Nice lib, I've been using for a little while.

I found this bug with map which doesn't behave the same as I'd expect from Ramda.js, perhaps there's something I'm missing?

print(
        pipe(
            map(lambda value: value + 1),
        )([1, 2, 3, 4, 5, 6, 7, 8, 9]),
    )

This gives me the error:

Traceback (most recent call last):
    map(lambda value: value + 1),
TypeError: map() must have at least two arguments.

Wrong result for aperture

Hi, I found this problem

ramda.aperture(2, [1, 2, 3, 4, 5, 6]) should return [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] but it returns [[1, 2], [2, 3], [3, 4], [4, 5], [6]]

Versioning: Why the change from semver to time?

Hello! 👋

Our company uses ramda as part of our stack and dependabot notified us that you published a new version for ramda just recently.

We noticed that you changed your versioning from semver to date of publishing. Why did you make that choice?
For us end users it removes some of the explicitness in the nature and scope of changes introduced, and requires a better readout of the commits & changeset. It's never really a bad thing to better understand your deps, but you know how it goes; can't be going to read the code like that for all our deps ;)

Could you please move back to semver?

Thank you!

adjust/update don't work as expected

Hello,

I noticed that adjust doesn't work as expected. From the ramdajs docs:

R.adjust(1, R.toUpper, ['a', 'b', 'c', 'd']);      //=> ['a', 'B', 'c', 'd']
R.adjust(-1, R.toUpper, ['a', 'b', 'c', 'd']);     //=> ['a', 'b', 'c', 'D']

In Python:

>>> adjust(1, to_upper, ['a', 'b', 'c', 'd'])
['a', 'b', 'c', 'd']
>>> adjust(-1, to_upper, ['a', 'b', 'c', 'd'])
['a', 'b', 'c', 'd']

Also, the negative index version of update doesn't work as expected. From the ramdajs docs:

R.update(1, '_', ['a', 'b', 'c']);      //=> ['a', '_', 'c']
R.update(-1, '_', ['a', 'b', 'c']);     //=> ['a', 'b', '_']

In Python:

>>> update(1, '_', ['a', 'b', 'c'])
['a', '_', 'c']
>>> update(-1, '_', ['a', 'b', 'c'])
['a', 'b', 'c']

Thank you.

`use_with` fails if one of the transformers is a `lambda` function

The following test case is failing:

def test_use_with():
    def add(x, y):
        return x + y

    two = R.use_with(R.add, [lambda x: x, R.identity])(1, 1)
    assert two == 2

probably because the current implementation of use_with is expecting named functions as transformers.
This wouldn't be so bad if not for e.g. pipe returning a lambda function that cannot be used as a transformer.

PS: @slavaGanzin coming back to python after a year in javascript land where I learned to love fp in general and ramda in particular, I am incredibly grateful for the work you have done here!

path_or exception on None Type

Nice work for making this Gem, @slavaGanzin!

Found a little issue with path_or. Not sure if this is a bug or not.

R.path_or(42, [0, 1], [None])
It would throw an exception
In [84]: R.path_or(42, [0, 1], a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-84-80b69f40b48b> in <module>
----> 1 R.path_or(42, [0, 1], a)

xx/python3.8/site-packages/toolz/functoolz.py in __call__(self, *args, **kwargs)
    301     def __call__(self, *args, **kwargs):
    302         try:
--> 303             return self._partial(*args, **kwargs)
    304         except TypeError as exc:
    305             if self._should_curry(args, kwargs, exc):

xx/python3.8/site-packages/ramda/path_or.py in path_or(default, path, value)
      9     value at that path. Otherwise returns the provided default value"""
     10     try:
---> 11         return default_to(default, _path(path, value))
     12     except (KeyError, IndexError):
     13         return default

xx/python3.8/site-packages/toolz/functoolz.py in __call__(self, *args, **kwargs)
    301     def __call__(self, *args, **kwargs):
    302         try:
--> 303             return self._partial(*args, **kwargs)
    304         except TypeError as exc:
    305             if self._should_curry(args, kwargs, exc):

xx/python3.8/site-packages/ramda/path.py in path(keys, dict)
      9     current_value = dict
     10     for key in keys:
---> 11         current_value = current_value[key]
     12     return current_value

TypeError: 'NoneType' object is not subscriptable

For RamdaJs, the result is expected:

R.pathOr(42, [0, 1], [null]); // => 42

Do you think this issue could be fixed by add TypeError to below L12?

@curry
def path_or(default, path, value):
"""If the given, non-null object has a value at the given path, returns the
value at that path. Otherwise returns the provided default value"""
try:
return default_to(default, _path(path, value))
except (KeyError, IndexError):
return default

CI is broken.

CI seems to be not working because some config is missing.
As github actions are working very well as a CI provider for projects hosted on github (and are completely free for open source projects) I would suggest, we set it up. Also, If you agree, I would volunteer to do that. Let me know what you think.

Kind Regards

`apply_spec` only works once

For example:

assert (
    R.map(
        R.apply_spec(
            {
                "foo": R.prop("bar"),
            }
        ),
        [{"bar": 1}, {"bar": 2}],
    )
    == [{"foo": 1}, {"foo": 2}]
)

fails because it returns [{"foo": 1}, {"foo": 1}]

map failed to work with 3.10

@curry
def map(f, xs):
    if isinstance(xs, collections.Mapping):
        return dict([(k, f(v)) for k, v in xs.items()])

    return [f(x) for x in xs]
AttributeError: module 'collections' has no attribute 'Mapping'

Calling prop_or may crash in `return o[name]` of prop.py

ramda==0.6.0

This problem happens under the following circumstances:

  • you call prop_or on a Python object that is not a dictionary
  • the property does not exist on this python object

In this case ramda will try to treat it as a dictionary and call o[name]. In itself that is correct - because o might be a dictionary - but the code should not crash if o is not a dictionary.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.