
Use JSON files as if they are Python modules - bane
https://github.com/kragniz/json-sempai/tree/master
======
jamesdutc
The mechanism is called "import hooks":

[https://docs.python.org/3/reference/import.html#import-
hooks](https://docs.python.org/3/reference/import.html#import-hooks)

[https://www.python.org/dev/peps/pep-0302/](https://www.python.org/dev/peps/pep-0302/)

You can see the import hook added here:

[https://github.com/kragniz/json-
sempai/blob/master/jsonsempa...](https://github.com/kragniz/json-
sempai/blob/master/jsonsempai/magic.py#L5)

Import hooks are a great feature in Python.

Take the `import` mechanism in the language and reduce it to its barest
theoretical formulation - what does it really do? (Name binding.) Think of all
the other features in your application that can be reduced to this. (e.g.,
configuration management) Use the constraints of the import mechanism to guide
the design of this feature, and use import hooks to implement it. You'll end
up with an implementation that is very "close" to the core language. I would
assert that this closeness strongly suggests correctness and composability.

Less philosophically, think of the Python virtual machine as a system with
lots of "safety valves" and "escape hatches." Import hooks are one such safety
valve. Think about all the things you could do easily by hooking into module
importing? (Real use-cases: loading code from bitemporal object databases,
deprecation of modules, relocation of modules, configuration management, &c.)

Of course, there are languages that are much more flexible than Python in this
respect. Python aims for a practical flexibility, and I find that, in
practice, Python strikes a nice balance.

~~~
orf
Import hooks are awesome, one of the cool things you can do is re-write the
code as you load it. I made a toy loader that automagically inlines (some)
Python function calls[1]. There are also cool projects like MacroPy[2] that do
much more extensive things.

1\. [https://tomforb.es/automatically-inline-python-function-
call...](https://tomforb.es/automatically-inline-python-function-calls)

2\. [https://github.com/lihaoyi/macropy](https://github.com/lihaoyi/macropy)

~~~
dr_zoidberg
I read your experiment on inlining and it looks quite interesting. Did you do
a benchmark on how it affects (improves?) performance? In my line of work I've
found ocasionally places where inlining would've helped (functions that do
masking with 64 bit masks, for example, are a mess to "inline by hand" and
kill a lot of readability and clarity). Even with the current limitations of
your "toy" implementation, it seems like it would help to avoid the costly
function calls.

------
jstoiko
My favorite is this issue: [https://github.com/kragniz/json-
sempai/issues/7](https://github.com/kragniz/json-sempai/issues/7)

> Ever since I saw this I have been unable to sleep. Please fix.

~~~
sarciszewski
> Works as intended. _adds the 'wontfix' label_

This is gold.

~~~
cjslep
The 'wontfix' label looks more like a yellow than a gold to me.

------
hyperion2010
IIRC there is a moment of sheer terror in this talk by David Beazley [0] where
he shows how to import an xml file as a python module.

0\.
[https://www.youtube.com/watch?v=0oTh1CXRaQ0](https://www.youtube.com/watch?v=0oTh1CXRaQ0)

------
vog
From the examples:

    
    
        >>> from jsonsempai import magic
        >>> from python_package import file
        >>> file
        <module 'python_package.file' from 'python_package/file.json'>
    

I believe it is not a good idea to teach people to import something named
"file", as that overrides Python's builtin class "file".

(On the other hand, that class is usually instantiated via calls to "open", so
the class name "file" is unused is most programs dealing with files.)

~~~
aleri
Also, 'file' doesn't exist in Python 3.

------
nemothekid
Really love the fact the import is named `from jsonsempai import magic`.

If this were to be used seriously, it would make sense to other devs that the
import named magic is doing some crazy stuff.

------
latenightcoding
I did the same with Perl in 10 minutes:
[https://git.io/vzKDs](https://git.io/vzKDs)

it was fun I will check it tomorrow when I'm back from the pub

~~~
viraptor
Is there any practical difference between that and just a normal new()
function returning a hash based on that json? Does bless change anything?

I mean, for "the same" I'd expect something like:

    
    
        ....
        use test
        say test->hello;
        say test->this->could->be->a->bad;

~~~
latenightcoding
Ok, back from the pub and fixed it you can now use it like this:

use BlessJSON qw(test.json);

say test->hello;

say test->this->could->be->a->bad;

close enough

------
arthurcolle
Why do all the comments act like this is bad? Seems fine to me. Explanation
would be appreciated :)

~~~
ben336
You're changing the behavior of import. So if somebody else were to remove the
seemingly unused `from jsonsempai import magic` the file would stop working as
expected.

Non obvious "magic" code like that tends to be frowned on in general, and
especially in the python community

~~~
fbukevin
Is it be useful? Or there are some alternatives to import JSON as a module as
easy as this one does?

~~~
nickles
For files:

    
    
        import json
        with open("foo.json") as f:
            foo = json.load(f)
    

For strings:

    
    
        import json
        bar = '{"foo": "bar"}'
        foo = json.loads(bar)

~~~
rileymat2
Does that respect import search paths? Does the original?

~~~
adrusi
There is no good reason to load json from import paths. Your import paths
should contain code, assets, not configuration.

~~~
icebraining
A JSON document might be an asset, such as static data. In fact, I'd much
rather have a Python file as configuration and JSON as data than the opposite.

------
BinaryIdiot
As a JavaScript developer for the past 5 years or so, when jumping into Python
I certainly miss the simple require(<json file>) which this seems to replicate
into Python pretty well!

Having said that I don't think that I would use it for serious things since
this isn't really the Python way and I would like my code to be most
understood by others. Neat though!

~~~
aikah
JSON stands for JavaScript Object Notation , not Python Object Notation.
Furthermore "require" is "proprietary" to nodejs, ES2015 has a different
module system and it will be the official js module system.

~~~
russjr08
> JSON stands for JavaScript Object Notation , not Python Object Notation.

That does not mean it shouldn't be used anywhere else.

------
hobarrera
> Disclaimer: Only do this if you hate yourself and the rest of the world.

I'm curious why the author would do this. Just for the fun in it?

~~~
jzelinskie
Likely for the fun and it might just save time when writing one off scripts or
using the interpreter.

I nearly spit my drink out at the name, though.

------
amelius
The enormous downside to this approach is that once you want to load a json
file dynamically, e.g. with a filename that comes from a dynamic string,
you're stuck and you have to come up with a completely different approach and
rewrite your code.

~~~
njharman
Not correct.

Like many things in Python import is actually just syntactic sugar for a
dunder function.

[https://docs.python.org/3/library/functions.html#__import__](https://docs.python.org/3/library/functions.html#__import__)

------
StavrosK
Excepting the cringemarsh that is "import <jsonfile>", this is actually very
useful. This looks very unpythonic:

my_json["this"]["can"]["be"] == "nested"

and is impossible to write defensively and cleanly after the first call:

my_json.get("this", {}).get("no way to not crash here")

Something that could do:

my_json.this.can.be == "nested"

With a default value would be very useful. Does anyone know something like it,
or should I whip a module up in an hour?

~~~
dadrian
I've taken a crack at something similar, I'd love to see what you came up
with. I ended up with this super-meh solution:
[https://github.com/zmap/ztag/blob/master/ztag/transform.py#L...](https://github.com/zmap/ztag/blob/master/ztag/transform.py#L7)

~~~
StavrosK
My thing turned out to be pretty much the same as yours, also equally meh:

[https://github.com/skorokithakis/jsane](https://github.com/skorokithakis/jsane)

There's no code there, but the underlying class is pretty much spot on yours.
I'm still trying to improve the API, but it's not looking great.

------
zippoxer
> Have you ever been kept awake at night, desperately feeling a burning desire
> to do nothing else but directly import JSON files as if they were python
> modules

I almost died laughing at this. Feels like the author is aware that this
scenario is probably the only one where such library can be mission critical.

~~~
erikb
Funny cause it's true. It's really something I desperately seeked a few years
ago

~~~
jason_s
... ??? why? What's wrong with json.loads()?

------
kelvin0
Awesome, although I don't quite have a use for it right now. Next we could: *
Import HTML/CSS/JS/DOM via a URL:
[https://news.ycombinator.com](https://news.ycombinator.com)

* Import XML? * Import any_structured_data!

------
moonpompey
Ah. kragniz must be the Damien Conway of Python.

------
bsg75
I'm not sure which is the better/worse idea:

"JSONx is an IBM® standard format to represent JSON as XML. The appliance
converts JSON messages that are specified as JSON message type to JSONx. The
appliance provides a style sheet that you can use to convert JSONx to JSON."

[https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/...](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)

------
PaulHoule
... and I was writing SPARQL queries against my Java source code yesterday

------
jm666
These jokes are getting rather sophisticated. For a few (head-scratching)
minutes, I thought this was meant seriously.

------
brhsiao
Some people are saying JSON ≠ Python Object Notation. Here we go!
[https://github.com/brhs/pon](https://github.com/brhs/pon)

(I used OP's work as a reference. Amazing you can do this in so few lines of
code.)

~~~
w_t_payne
It's official. PON is now _a thing_.

