GithubHelp home page GithubHelp logo

Comments (20)

scoder avatar scoder commented on July 26, 2024

Shouldn't you be more interested in the Lua type of the object than the type of the Python wrapper? See

https://github.com/scoder/lupa#python-objects-in-lua

from lupa.

kmike avatar kmike commented on July 26, 2024

Thanks, it will work for my use case!

The problem with it is that "Python instincts" don't help here: from lua.eval("{}") you get <Lua table at 0x7f813059ec40>; you can get a class from this object (<type 'lupa._lupa._LuaTable'>), but this class doesn't exist is not importable in Python land, so it is not obvious how to check for a type.

By doing isinstance check one can confirm that an object conforms to a certain interface. Interface is provided by lupa wrapper, not by Lua language, so checking for Lua type is less explicit.

from lupa.

kmike avatar kmike commented on July 26, 2024

Faced another issue: you need a LuaRuntime instance to do a check. It may be hard to structure code in such way an instance is accessable everywhere; there could be many LuaRuntime instances managed by another part of the library, and no globally available runtime - it could be inconvenient to pass "lua" object through several layers to do a type check. Creating another Lua runtime just for type checking doesn't look good doesn't work.

from lupa.

scoder avatar scoder commented on July 26, 2024

Two ideas:

  1. provide _LuaObject with a property .lua_type that returns the Lua type name (as done in __repr__())

  2. provide a global function lupa.lua_type() that takes a _LuaObject and returns its Lua type name (independent of a specific runtime instance)

I vote for 2) as it avoids adding a new attribute to wrapped Lua objects that risks shadowing a Lua object attribute or table key.

The type of the wrapper object should never be relevant. It's a pure implementation detail, as shown by the fact that the types are not exported by the module.

from lupa.

kmike avatar kmike commented on July 26, 2024

The type of the wrapper object should never be relevant. It's a pure implementation detail, as shown by the fact that the types are not exported by the module.

My use case is serializing/processing a dict which contains mixed values - some of them could be wrapped Lua objects, some of them could be Python objects. I want to expand tables to dicts, disallow (raise an exception) Lua functions and coroutines, stuff like that. Values are mixed because they are returned from Lua code which has an access to some of the Python objects and can put them to a table.

Is there a better way to distinguish between regular Python objects and wrapped Lua objects than doing an isinstance(obj, LuaObject) type check? lupa.lua_type() could help with that as it will return 'userdata' for regular Python objects, but if I'm not mistaken it could return 'userdata' for objects from Lua extensions as well.

What is an advantage of hiding these wrapper classes - do you have plans to change or remove them?

from lupa.

kmike avatar kmike commented on July 26, 2024

It keeps bothering me :) User should care about lua types in Lua code and about Python types in Python code, right?

In #34 you mentioned that it'd be good for _LuaTable to provide update method; this method is to be used from Python code, Lua tables don't have this method, so checking for lua_type(obj) == "table" is less clear.

I propose to remove @cython.internal from types that can be visible to Python: _LuaTable, _LuaObject, _LuaFunction, _LuaCoroutineFunction, _LuaThread, _LuaIter.

from lupa.

scoder avatar scoder commented on July 26, 2024

Counterproposal :)

We register them with the corresponding ABCs so that you can test isinstance(obj, Mapping), isinstance(x, Callable) etc. Wouldn't that be enough?

from lupa.

kmike avatar kmike commented on July 26, 2024

Registering them with ABCs still won't allow to distinguish between "regular" Python objects and wrapped Lua types. lupa.lua_type() cover most practical needs, but it doesn't provide a way to check if an object is a LuaObject or not.

from lupa.

scoder avatar scoder commented on July 26, 2024

Ok, but that can be helped with a global function lupa.is_lua_object(obj).

from lupa.

kmike avatar kmike commented on July 26, 2024

It looks like lupa.lua_type(obj) + lupa.is_lua_object(obj) will cover all use cases.

I haven't understood yet why is this indirection needed - do you want to keep a possibility of changing/removing _Lua... classes without breaking user code, is that what this indirection for?

from lupa.

kmike avatar kmike commented on July 26, 2024

And if this indirection is needed, why is it better to rely on strings like "table" instead of e.g. using custom ABCs, or classes directly?

from lupa.

scoder avatar scoder commented on July 26, 2024

I consider the concrete classes an implementation detail that code should not depend on. I don't see a need to depend on anything but a) the Lua type of the wrapped object and b) the protocol(s) that the object wrapper implements in Python. And I do encourage people to test for ABCs, thus my proposal to add support for them.

from lupa.

kmike avatar kmike commented on July 26, 2024

I agree that there is no need for anything but Lua type of a wrapped object and a protocol(s) that the object wrapper implement, they cover all use cases.

My point is that isinstance(obj, lupa.LuaTable) also covers all use cases (it checks for both in a single call), and it provides some advantages:

  • it is easier to implement - we need to remove some code instead of adding more code;
  • lupa.lua_type(obj) == "table" doesn't check that "table" is a valid value while isinstance(obj, lupa.LuaTable) will raise an AttributeError in case of incorrect/unavailable type;
  • from repr(wrapped_object) users can understand how to use isinstance(obj, lupa.LuaTable), but not how to use lupa.lua_type(obj).

from lupa.

scoder avatar scoder commented on July 26, 2024

I get the impression that you are confusing two levels here: the Python API and the Lua API. The fact that an object is a table in Lua doesn't necessarily mean it gets a mapping interface wrapper in Python. This may become configurable at some point, and users may be able to decide which interface to map a Lua object to (just like we have as_attrgetter() and as_itemgetter() now). A possible example would be to split up sequence and mapping support for tables and provide separate, distinct wrapper implementations for them. These interfaces may or may not reuse what the current Lupa wrapper classes provide (although they would most likely inherit from a Lupa wrapper base class in one way or another).

If your code relies on a specific Python interface, you should test for the ABC. If you rely on specific properties of the wrapped Lua object, you should test for that based on the Lua type. You should not test for a specific wrapper class.

from lupa.

scoder avatar scoder commented on July 26, 2024

I just realised that there is no need for is_lua_object() if lua_type() returns None for non-Lua objects.

from lupa.

kmike avatar kmike commented on July 26, 2024

hmm, github haven't displayed some of your comments before (#26 (comment), #26 (comment)).

What I really want to do is to get an object returned by Lua function and convert it to plain Python data structure which doesn't hold any reference to LuaRuntime, and can be e.g. serialized to JSON:

  • (previously wrapped) Python objects should remain Python objects, they should be passed as-is;
  • Lua tables should be copied to Python dicts (with keys and values converted from Lua recursively);
  • exception should be raised for other wrapped Lua objects.

A possible example would be to split up sequence and mapping support for tables and provide separate, distinct wrapper implementations for them.

This is quite similar to what I'm doing - I want to expose _LuaTables as unrelated (copied) dicts. Checking for _LuaTable is exactly what the code wants to do; it doesn't care what is Lua type of the object or if object is a Mapping or not. If lupa returns some other wrapped Lua object then it is not known how to convert it to a primitive data type, so an exception should be raised; again, the code doesn't care about its Lua type or interfaces this object provides, what it cares about is if an object is _LuaObject or not.

I just realised that there is no need for is_lua_object() if lua_type() returns None for non-Lua objects.

This could become confusing with auto-conversion rules. I'd expect is_lua_object to return False for Python ints, but lua_type returns 'number' for ints. Should this new lua_type return None or 'number' for a Python int?

from lupa.

scoder avatar scoder commented on July 26, 2024

See 9f12ac0

from lupa.

kmike avatar kmike commented on July 26, 2024

OK, it makes sense.
Maybe fix/change lua_type example in README?

from lupa.

scoder avatar scoder commented on July 26, 2024

9bdd1e4

from lupa.

kmike avatar kmike commented on July 26, 2024

Thanks!

from lupa.

Related Issues (20)

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.