J Object
A global j object for easy access to components and functionalities (e.g. god object anti-pattern).
- Should allow auto-completions (without the need to evaluate!)
- Easy to register objects/components.
Use modules
Utilize code structure to get the idea of a global j object, by simply arranging modules like:
jumpscale
mod
submod
impl.py
impl.py
class CoreImpl:
....
core = CoreImpl()
Accessing from other places
import jumpscale as j
j.mod.submod.impl.core
Other principles like state management need to be discussed (also make sure it would cover actual jumpscale usescaes).
Problem 1: Code Structure
We can use namespaces the way zope
does with zope.interface for example.
Now we can easily have jumpscale.sal
, jumpscale.clients
easily separated into there own pip packages like any normal python project. (bye bye installtools!)
declaring namespaces
One of two ways
1- remove __init__.py
2- add namespace declaration in __init__.py
__import__('pkg_resources').declare_namespace(__name__)
Example structure
.
├── projectclients
│ └── jumpscale
│ ├── clients
│ │ ├── github.py
│ │ ├── gogs.py
│ │ ├── __init__.py
│ ├── __init__.py
├── projectmain
│ └── jumpscale
│ ├── loader.py
│ ├── __init__.py
├── projectsals
│ └── jumpscale
│ ├── __init__.py
│ └── sal
│ ├── fs.py
│ ├── __init__.py
└── projecttools
└── jumpscale
├── __init__.py
└── tools
├── __init__.py
└── sync.py
Problem 2: implicit imports (autoloading subpackages)
jumpscale by design wants the least amount of imports thats why all are registered under j
e.g for sal/__init__.py
import pkgutil
__all__ = []
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
__all__.append(module_name)
_module = loader.find_module(module_name).load_module(module_name)
globals()[module_name] = _module
CHECK: lazyloader/import hooks in stdpython https://docs.python.org/3/library/importlib.html#importlib.util.LazyLoader
Problem 3: Singletons
Solved by design using python modules
Problem 4: jslocation
If we do like the following
import jumpscale.sal
import jumpscale.tools
import jumpscale.clients
j = jumpscale
we have handcrafted imports for sal, tools, clients so their subpackages can be autoloaded, but how should it work with packages like digitalme
How to register digitalme in the global object "j"
Do we generate import jumpscale.digitalme
? is there a standard python way to do it? a reliable plugin system?
where would its module be registered?
for instance there might be digitalme.tools
should it be under j.tools
directly or j.digitalme.tools
? I prefer the latter for clarity and conflict resolution too
Example usage with jumpscale
~> export PYTHONPATH="projecttools:projectsals:projectclients:projectmain"
In [1]: import jumpscale.loader
In [2]: jumpscale.sal.fs.copyfile('a', 'b')
copying file
In [3]: jumpscale.tools.sync.sync()
sync tool
In [4]: jumpscale.clients.github.get_githubclient?
Signature: jumpscale.clients.github.get_githubclient(username, password)
Docstring: <no docstring>
File: ~/wspace/jumpscale-skeleton/projectclients/jumpscale/clients/github.py
Type: function
In [5]: jumpscale.clients.github.get_githubclient('a', 'bb')
getting client with a bb
In [6]: jumpscale.clients.gogs.get_gogs('a', 'bbb') # uses jumpscale sal.fs in its code
sync tool
getting gogs client with a bbb
Example usage with j
In [1]: from jumpscale.loader import j
In [2]: j.sal.fs.removefile('a')
removing file
In [3]: j.clients.gogs.get_gogs('a', 'b')
sync tool
getting gogs client with a b