I am trying to modify a better_profanity
library to include an additional argument to get_replacement_for_swear_word
function. To do so I first import the necessary parts of the library and test its functionality before:
from better_profanity import profanity, Profanity text = "Nice c0ck" censored = profanity.censor(text) print(censored)
Now I get the source code of the class method, modify it and execute it to __main___
:
from inspect import getsource new_hide_swear_words = getsource(profanity._hide_swear_words).replace( 'get_replacement_for_swear_word(censor_char)', 'get_replacement_for_swear_word(censor_char, cur_word)').replace( 'ALLOWED_CHARACTERS', 'self.ALLOWED_CHARACTERS' ) # fixing the indent new_hide_swear_words = 'n'.join(i[4:] for i in new_hide_swear_words.split('n')) exec(new_hide_swear_words)
Now I replace this function inside the class:
profanity._hide_swear_words = _hide_swear_words.__get__(profanity, Profanity)
Note that I swap ALLOWED_CHARACTERS
for self.ALLOWED_CHARACTERS
. This is because the author of the library has imported ALLOWED_CHARACTERS
in the same file where the class is defined, so when I swap the function and try to run the first piece of code again, it sais that this variable is not defined. It just so happens that it is stored in self
as well, but there is no such luck with several other imported modules. Any ideas how to tackle this?
Here is the class definition on github.
Advertisement
Answer
When you run exec(new_hide_swear_words)
, you define the function _hide_swear_words
in your current module (that’s why you can access it later with just _hide_swear_words
).
That however means, that the function lives fully in your module, so when you call it indirectly with profanity.censor(some_text)
it will run the function inside this module and look for all dependent global symbols in your module.
That’s why it can’t access the variable ALLOWED_CHARACTERS
or the function any_next_words_form_swear_words
. They are defined in the profanity module, but not in your module where you run the exec.
One way to solve this, would be to just import all symbols into your module.
from inspect import getsource from better_profanity import Profanity, profanity from better_profanity.constants import ALLOWED_CHARACTERS from better_profanity.utils import * new_hide_swear_words = getsource(profanity._hide_swear_words) new_hide_swear_words = "n".join(i[4:] for i in new_hide_swear_words.split("n")) exec(new_hide_swear_words) profanity._hide_swear_words = _hide_swear_words.__get__(profanity, Profanity) text = "Nice c0ck" censored = profanity.censor(text) print(censored)
Another way would be to execute the function in the profanity module itself (then all the symbols are already defined).
However that also has a little overhead. E.g. you have to import the module and pass it to the exec
function, and afterwards you need to extract the function from the module (as it will be defined in that module).
from importlib import import_module from inspect import getsource from better_profanity import Profanity, profanity new_hide_swear_words = getsource(profanity._hide_swear_words) # fixing the indent new_hide_swear_words = "n".join(i[4:] for i in new_hide_swear_words.split("n")) profanity_module = import_module(Profanity.__module__) exec(new_hide_swear_words, vars(profanity_module)) profanity._hide_swear_words = profanity_module._hide_swear_words.__get__( profanity, Profanity ) text = "Nice c0ck" censored = profanity.censor(text) print(censored)
profanity_module = import_module(Profanity.__module__)
is the same thing as import better_profanity.better_profanity as profanity_module
.