How can I hook a function in a python module? - python

So I have a package in my virtual environment installed in the site-packages folder of it.
In that package there is a module with a bunch of functions, I want to change one of these functions without touching the package code, so I want to make a hook of that module and then change/overwrite the function so it behaves in the way I want.
I don't know if this is even posible in python (I'm new to the language)
Example:
I have a package called their_package in my site-packages folder, inside I have a module named whatever.py with the following code:
import sys
import os
def this_is_a_function(parameter):
//whatever logic in here
return result
What I want is to hook the whatever.py module so I can redefine the this_is_a_function to have a diferent logic. Is this posible? I would appreciate a lot a code sample!
Thank you in advance!:)

You can redefine your function with:
import whatever
def this_is_a_function(parameter):
pass
whatever.this_is_a_function = this_is_a_function

Related

I'm creating my first module, and i wanted to know (in the most layman terms please) where i get to name the module

is it the "name" in the setup.py gets to be the name of the module?
so in this instance when i use this module is the code going to be written as "from myfirstmodule import siblings_game enter image description here?
the other modules ive tried creating have nor worked when applied to flask ( the next part of the textbook is to create a webapp) and i am trying to find the root of the priblem. idk if im not importing the right name.
Start at the start. All that's needed to write a module in Python is naming a file like my_mod.py:
print('Hello')
Now this code will execute the module (once):
import my_mod
If you have anything named in your module, it can be referenced on the module, or imported directly, like this other my_mod.py:
def fun():
...
ten = 10
Now this works:
import my_mod
my_mod.fun()
from my_mod import ten
print(ten)
Once you're comfortable with that, you can put the module in an appropriately named folder, add an __init__.py and you have the beginnings of a package. The package can be provided with a setup.py and that allows you to specify more relevant metadata about the package, like what its requirements are, what platform it is for, etc.
And once you have your package, you can turn that into a wheel (.whl) file, or publish it on a service like PyPI and use it in any other application, by installing it. That can be a web application, or any other type of application.
The name attribute is the name of your package. It is the identifier that you or someone else will have to import in order to use its functionality, just like you say:
import myfirstpackage
from myfirstpackage import myfirstfunction
If your package is not correctly imported, chances are that Python can find it from your working directory, or that your "package" isn't a package at all! (Have you added an __init__.py file to myfirstpackage/ ?)
Other than that, you may have to repost a question showing exactly what you are doing.

Importing modules dynamically in Python 3.X

I would like to import a module from inside a functions. For example from this:
from directory.folder.module import module
def import():
app.register_blueprint(module)
To this:
def import():
from directory.folder.module import module
But, without hardcoding it. For example:
def import():
m = "module"
from directory.folder.m import m
Is it possible? Thanks in advance
You want the importlib module.
Here's the most simplistic way to use this module. There are lots of different ways of weaving the results of calls to the module into the environment:
import importlib
math = importlib.import_module("math")
print(math.cos(math.pi))
Result:
-1.0
I've used this library a lot. I built a whole plug-in deployment system with it. Scripts for all the various deploys were dropped in directories and only imported when they were mentioned in a config file rather than everything having to be imported right away.
Something I find very cool about this module is what's stated at the very top of its documentation:
The purpose of the importlib package is two-fold. One is to provide the implementation of the import statement (and thus, by extension, the import() function) in Python source code.
The intro in the 2.7 docs is interesting as well:
New in version 2.7.
This module is a minor subset of what is available in the more full-featured package of the same name from Python 3.1 that provides a complete implementation of import. What is here has been provided to help ease in transitioning from 2.7 to 3.1.
No, python import does not work this way.
Such as an example you try to import a module named mod, so you run import mod. Now interpreter will search for mod.py in a list of directories gathered from the following sources:
The directory from where the input script was run or the current directory if the interpreter is being run interactively.
The list of directories contained in the PYTHONPATH environment variable, if it is set. (The format for PYTHONPATH is OS-dependent but should mimic the PATH environment variable.)
An installation-dependent list of directories configured at the time Python is installed.
So if you have a variable named m='mod' and run import m it will search for m.py not mod.py.
But just a silly dangerous workaround is to use exec() (WARNING FOR MALICIOUS INPUT)
m = "module"
exec(f'from directory.folder.m import {m}')
If you don't mind external modules try importlib.
You can use the importlib module to programmatically import modules.
import importlib
full_name = "package." + "module"
m = importlib.import_module(full_name)

Cannot import module in same directory and package

I'm using a from . import module statement to do exactly that: import a local module to my script. The script and module reside in the same folder.
# module.py
def foo():
print('Foo!')
# script.py
from . import module
module.foo()
> ImportError: cannot import name 'module'
This should be pretty easy, and doing just import module does work, but as this answer suggests one should, I modified the statements to the former form.
The end goal is to have a package, from which I can use things, but also to have executable scripts inside the package that import other parts of that package. Apparently, after a few days worth of searching and a few questions I still don't quite understand the import and packaging machinery.
These might be the cause:
Import statements are different in 2.7 and 3.x, I'm using 3.6, the question was on 2.7
Relative imports are different inside packages (folder with __init__.py)
The working directory is different or the folders are not in sys.path
Having an __init__ file does not make a difference at least in a fresh project in PyCharm. Also, the working directory is set to the folder of the sources and it is in path.
Have I missed something? Or rather, what's the correct way of achieving the functionality described in the end goal? Any help is greatly appreciated!
Since writing this answer I have realised it is more convenient and better style in my humble opinion to install the package with pip install -e . and use absolute imports. So even within a package writing from package.sub.module import thing. This makes refactoring a lot easier and there's no need to ever manipulate module variables or sys.path.
When running a script directly, Python consideres the name (a special variable, __name__) of that script to be "__main__". In case of an import, the name is set to the name of the module. In the latter case relative imports are fine. But import actually looks at the combination of __name__ and another special variable, __package__, which is None for an executed script, but the path to a module for an imported module, e.g. parent.sub.
The searched variable is... drumroll...
__package__ + '.' + __name__
The secret ingredient is manipulating __package__:
# script.py
__package__ = 'package_name' # or parent.sub.package
from . import module
This lets Python know you are inside a package even though the script is executed directly. However, the top level folder needs to be in sys.path and the package name has to reflect that directory structure.
See this very comprehensive answer on the topic of relative imports.

imp.load_source() in Python

When is it useful to use imp.load_source() method for importing Python module? Has it some advantage in some scenario in opposite to normal importing with import keyword?
import always looks in the following order:
already imported modules
import hooks
files in the locations in sys.path
builtin modules
If you want to import a module which would not be found by any of these mechanisms, but you know the filename, then you could use imp.load_source(). Or if you want to import a module that would be shadowed by an earlier import mechanism, for example if you want to import foo from a directory in sys.path but there is a custom import hook that would find its own version of foo first, then you could use imp.load_source() for that too. Basically it lets you control the source of the module's code in a way that import does not.

Libraries act differently depending on if they are installed or not

I have a Python library I wrote which has been acting up on me. I have a set of variables which change the way the library works. In testing it all worked fine, but when I python lib.py install the variables have no effect on the library. I broke this down to the simplest example possible:
Library:
##lib.py
config="Original"
def run():
print config
Script:
import lib
lib.config="New"
lib.run()
print lib.config
If you place the library in the same directory as the script and run it the output is:
New
New
But if you install the library and then try the script using the library from the dist-packages the output is:
Original
New
Could someone explain what is going on? I'm a bit confused and terribly interested in the happenings and reason. Additionally am I doing programatical configuration totally wrong?
Edit
It turns out the problem is the init.py file. It's basically like importing a library that just imports another library. When you import an installed module it looks at the folder lib and the file init.py. init.py is just a one liner from lib import *. It simply pretends to be the actual library, but that causes an odd problem if you use a global variable. A simulated example of what is essentially going on:
##init.py
from lib import *
Script:
import init
init.config = 'New'
init.run()
print init.config
Output:
Original
New
The function run() looks for config in lib.py, but print init.config looks for it in init.py. Thanks for the help everyone. Fix is to change the way the module installs (no init.py). Eventually, I hope to remove all the global variables, but for the time being everything works perfect.
What you describe would be inconsistent with how Python works (read, if you like, "I don't believe you did precisely that and got precisely that result").
If you go importing lib from different places or in different ways, though, you could be ending up with two copies of it, either two copies of one of the modules or one of the current-directory lib and the other the installed lib. If you are getting this "Original"/"New" behaviour, that seems to me the most likely reason.

Categories

Resources