In python, "export" a custom-tailored object from a module - javascript

In JavaScript, specifically in node.js setting, one can spell module.exports = 13; in module.js, then x = import ("module.js"); elsewhere and have 13 assigned to x directly.
This saves some code when a module exports a single function, and I notice a lot of widely used packages (such as through2) make use of it.
Is there a way to do the same in Python? With some black magic, maybe?
I do have heard of a thing called loader that's, I guess, supposed to do some manipulations with a module before making it available. In particular, I think SaltStack makes use of something like that in salt.loader, but the code is too hard for me to follow. I imagine we could write a function similar to this:
def loader(module):
m = __import__(module)
return m["__exports__"]
— Then define __exports__ somewhere in a module we want to import and enjoy functionality very similar to JavaScript's module.exports mechanics. But unfortunately TypeError: 'module' object has no attribute '__getitem__' prevents us from doing that.

Python has importing built in to the language at a more basic level than Javascript does, almost all use cases are covered by a simple import statement.
For your example, all it really boils down to is:
from module import exports as x
So, there's not need to look for code savings by changing module.
The other part of the question is how, as a module author, would you restrict people to seeing only a single symbol.
Generally this is not required except to help users know what are public functions vs implementation details. Python has a few common idioms for this:
Any names that start with a leading underscore, such as _helper, are considered private. They can be accessed as normal, but the implication is you should not.
If a module level variable __all__ = [...] exists, only the strings it contains are considered public. The names must seperatedly be declared in the module.
As well as being documentation, both of these do affect one aspect of the module import:
from module import *
Using a star import is generally discouraged, but only public names will be brought in to the local namespace.

After some thinking I understood that, while we can't say m["__exports__"] due to module object's class not having __getitem__ method, we can still access some of the module's elements with "dot" notation: m.__exports__ works.
Another way: screen all module level names off with an underscore and assign the object to be exported to a variable named after the module, then from module import *.
loader.py:
def loader(module):
m = __import__(module)
return m.__exports__
exports.py:
def _f():
return 13
_a = 31
exports = {"p6": _f, "p8": _a}
__exports__ = exports
Python 2.7:
>>> import loader
>>> e = loader.load ("exports")
>>> e
{'p8': 31, 'p6': <function _f at 0x7fb79d494cf8>}
>>> from exports import *
>>> exports
{'p8': 31, 'p6': <function _f at 0x7fb79d494cf8>}
Python 3:
>>> import loader
>>> e = loader.load ("exports")
>>> e
{'p6': <function _f at 0x7f88ae229ae8>, 'p8': 31}
>>> from exports import *
>>> exports
{'p6': <function _f at 0x7f88ae229ae8>, 'p8': 31}
In the first way proposed, I unfortunately cannot use __all__ in loader.load to filter only listed names from a module being loaded since __getitem__ is not defined for module object.
In the second way proposed I don't get so much control (in that a malicious module can export arbitrary names and manipulate my namespace) and flexibility (in that I cannot assign the module's exported object to arbitrary name anywhere in my code).
So, there is still a bit left to be desired here.

Related

is there a way to import all keys inside a package with require?

I would like to know if there is a way to import all elements of a package/file without directly naming them
example:
//file1 - things.js
module.exports = {
thing1:{...},
thing2:{...},
thing3:{...}
}
//file2 runner.js
const things = require("./things")
console.log(things.thing1)
//in this case it imports the things.js and its elements and assigns the variable things,
//but that's not what I want
//I want it to import the native variables from the things.js file without having to pull each one individually
//---
//i know i can import the native variables by pulling them like this:
const { thing1, thing2 } = require("./things")
console.log(thing1, thing2)
//but this is not what I want either, what I want should look like the following example:
const {} = require("./things")
console.log(thing1, thing2, thing3)
//imporiting all native variables without having to define one by one
Short answer, no.
When using module.exports, you're effectively assigning a value to the return of require. That value can be any valid JavaScript value, in this particular case, an object. Presently, JavaScript does not have a mechanism for destructuring an object into all of its constituent keys, which is functionally what you're asking for.
In fact, JavaScript has no mechanism at all for implicit variable declaration, at least not in strict mode. If it doesn't appear in the source code, it's not there.
A hacky way around this could be something like this:
const thing = require('../thing.js');
for (const key in Object.keys(thing)) {
global[key] = thing[key]; // using "global" here instead of "window" for environment-agnostic code
}
This will force all of your exports to be available in the global scope, accessible as if they were declared. However, your editor/IDE will get very upset that it doesn't know where these variables came from, and this is horrific, unrecommendable practice.

Import/Export name collision resolution

Testing in Node JS the following modules layout, looks like local exported definitions always replace external exported in case of name collision (see f1 in B.js).
A.js
export const f1 = 'A'
B.js
export * from './A.js'
export const f1 = 'B'
C.js
import * as A from './A.js'
import * as B from './B.js'
console.log(A.f1)
console.log(B.f1)
> node C.js
// A
// B
Is this a rule? I have not found something about how to manage this in Ecmascript specs.
Does import/export order matter?
Do you see this as a reliable method for extending a module overloading functions and/or adding new ones?
Is this a rule? I have not found something about how to manage this in Ecmascript specs.
Yes, Local exports have priority. Which is, in fact, standardized in the spec:
For each ExportEntry Record e in module.[[LocalExportEntries]], do
a. Assert: module provides the direct binding for this export.
b. Append e.[[ExportName]] to exportedNames.
For each ExportEntry Record e in module.[[IndirectExportEntries]], do
a. Assert: module imports a specific binding for this export.
b. Append e.[[ExportName]] to exportedNames.
Specifically the starExport in your case is part of:
For each ExportEntry Record e in module.[[StarExportEntries]], do
(...)
c. Let starNames be requestedModule.GetExportedNames(exportStarSet).
d. For each element n of starNames, do
i. If SameValue(n, "default") is false, then
1. If n is not an element of exportedNames, then
a. Append n to exportedNames.
So, to answer your second question:
Do you see this as a reliable method for extending a module overloading functions and/or adding new ones?
Yes, it's reliable because it's specified in the standard.

ccall import of emscripten export in GHCJS

I'm trying to port the haskell library minisat to JavaScript using ghcjs, for integration in a larger haskell-ghcjs project.
minisat contains a couple of ffi imports from a c library. I've manged to compile the c library to javascript using emscripten, and to export the functions that minisat requires. So far, so good.
However, there are a couple of imports that look like this:
foreign import ccall safe minisat_solve :: Solver -> Int -> Ptr (Lit) -> IO (Bool)
which imports a function that looks like this:
int minisat_solve(minisat_solver *s, int len, minisat_Lit *ps)
My understanding, from the documentation, is that when emscripten exports a function that takes or returns a pointer, the pointer becomes a JavaScript number type.
The ghcjs documentation suggests that it should be possible to leave the existing foreign imports in place, by appropriately wrapping a JavaScript function. However, ghcjs represents pointer types as roughly a pair consisting of a JavaScript object and number.
I think the wrapper code should be roughly
function h$minisat_solve(...){
...
minisat_solve(...)
...
}
function minisat_solve = Module.cwrap('minisat_solve',...,...)
But I'm stumped by the type mismatch.
So, here's the challenge: Explain how to properly wrap an emscripten export for ccall import by ghcjs, using the above wrapper code as an example (or a counterexample, if I've got it completely wrong)
Pointer types can be converted to and from integers: https://hackage.haskell.org/package/base-4.10.0.0/docs/Foreign-Ptr.html#t:IntPtr . Thus, you ought to be able to convert to / from any format that emscripten requires using those functions.

Python private instance data revisited

I've read various "there is no truly private data in Python instances" posts, but we're all aware of using closures in Perl and JavaScript to effectively achieve private data. So why not in Python?
For example:
import codecs
class Secret:
def __private():
secret_data = None
def __init__(self, string):
nonlocal secret_data
if secret_data is None:
secret_data = string
def getSecret(self):
return codecs.encode(secret_data, 'rot_13')
return __init__, getSecret
__init__, getSecret = __private()
Now we do:
>>> thing = Secret("gibberish")
>>> thing.getSecret()
'tvoorevfu'
>>> dir(thing)
['_Secret__private', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getSecret']
What can you do to the instance thing to get read access to the original string (ignoring my weak encryption) or write access to it?
I'm teaching my students about Python classes this week and I'm trying to understand why, given closures, the techniques for JavaScript & Perl won't work for Python.
If you just want to access the original, it's not that hard, since Python function implement a rather thorough inspection api. You can access the original secret with something like this:
thing = Secret("gibberish")
# __init__ doesn't need to be used here; anything defined within the closure will do
thing.__init__.__func__.__closure__[0].cell_contents
And, hey! We get the original value.
It is harder---but not impossible---to modify the value (see here). Modified for this setup:
import ctypes
...
thing = Secret("gibberish")
cell = ctypes.py_object(thing.__init__.__func__.__closure__[0])
new_value = ctypes.py_object('whatever')
ctypes.pythonapi.PyCell_Set(cell, new_value)
thing.getSecret()
You wouldn't ordinarily do this but you can dig into the instance with module inspect.
>>> thing = Secret("gibberish")
>>> thing.getSecret()
'tvoorevfu'
>>> import inspect
>>> inspect.getclosurevars(thing.getSecret).nonlocals['secret_data']
'gibberish'
>>> inspect.getclosurevars(thing.__init__).nonlocals['secret_data']
'gibberish'
Given one of the functions within the closure, you can access the closure's variables. I haven't yet found a way to modify the variable.
So it's not impossible if you are willing to go to some effort. Why you would do that in the normal course of programming I don't know.

Is it possible to import variables in JavaScript (node.js)?

I have variables in app.js:
var G = {};
module.exports = G;
var DATA = G.DATA = 'DATA';
var F1 = G.F1 = function(val)
{
return val;
};
In this manner, I can export variables under the object G, and at the same time, can access the variable directly writing DATA without G. prefix.
So far so good.
Now, I want to run a test for app.js in test.js:
var G = require('./app.js');
console.log(G.DATA); // -> DATA
This works, but I also want to access the variable directly writing DATA without G. prefix like console.log(DATA); // -> DATA
Surely, I could do like
var DATA = G.DATA; for every variables(property) export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
Is there any way to do this automatically?
So far, I'm pessmistic since
JS function encloses var in the own scope, so in theory there's no way to have a helper function to var for every object property.
Thanks.
PS. I would like to avoid any eval or VM of node solution. I have tried them in past, and too much problems.
I could assign a local variables for every property export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
No, that's how it is supposed to work. You - and only you - are in charge of what local variables exist in your module scope. No changes in the "export variables" of an included module should break your code.
Accessing properties on the imported module (with a self-chosen name) is the way to go. This is quite equivalent to Python's import app or import app as g.
If you want some particular properties as local variables, you will usually choose them manually, as in Python's from app import DATA, F1. In JS, you will need a multiple var statement like the one you've shown in your question. However, there is a syntax feature called destructuring assignment which will make this more fluid. You can use this in JavaScript 1.7+ (Gecko), CoffeeScript, or EcmaScript 6:
var {DATA, F1} = require("app.js");
Is there any way to do this automatically?
Yes and No. You should not do this, but you can - just like Python's frowned-upon from app import *. To cite what they say, which is equally true for JavaScript:
[It] introduces an unknown set of names into the interpreter, possibly
hiding some things you have already defined.
Note that in general the practice of importing * from a module or
package is frowned upon, since it often causes poorly readable code.
However, it is okay to use it to save typing in interactive sessions.
In JavaScript, you can[1] use the with-statement:
with (require("app.js")) {
…
}
[1]: Not in ES5.1 strict mode, though - which is recommended for optimisation

Categories