Determine whether static file site contains css inheritance rule - css

I'm working on a site that renders static html files, and I wish to determine which pages in the site contain a specific css inheritance rule, such as .parent .child (a child class that descends from a parent).
I can imagine a web crawler that accesses each of those pages, runs a test to see whether the given page has that style, and returns a report, but are there any tools that already perform this work well for static file sites (e.g. not the css-tree-shake-plugin for webpack)? I'd be grateful for any insights others can offer on this question.

Here's what I came up with:
#!/usr/bin/env python
'''
from source:
pip install selenium
pip install beautifulsoup4
brew install phantomjs
usage: python shake_trees.py '_site' '.parent .child'
'''
from bs4 import BeautifulSoup
from selenium import webdriver
import sys, copy, multiprocessing, os, fnmatch
def clean_href(href):
return href.split('#')[0].split('?')[0]
def get_web_urls(all_links, visited):
recurse = False
for link in copy.copy(all_links):
if link not in visited:
visited.add(link)
driver.get(link)
for tag in driver.find_elements_by_tag_name('a'):
href = clean_href(tag.get_attribute('href'))
if domain in href and href not in visited:
recurse = True
all_links.add(href)
if recurse:
return get_web_urls(all_links, visited)
else:
print(all_links, visited)
return all_links
def get_static_site_urls():
matches = []
for root, dirnames, filenames in os.walk(root_url):
for filename in fnmatch.filter(filenames, file_match):
matches.append(os.path.join(root, filename))
return matches
if __name__ == '__main__':
# parse command line arguments
root_url = sys.argv[1]
css_selector = sys.argv[2]
# globals
domain = root_url
static_site = False if 'http' in root_url else True
file_match = '*.html'
# initialize the phantom driver
driver = webdriver.PhantomJS()
driver.set_window_size(1000, 1000)
if static_site:
urls = get_static_site_urls()
else:
driver.get( root_url )
urls = get_web_urls( set([root_url]), set() )
for url in urls:
if static_site:
url = 'file://' + os.path.join(os.getcwd(), url)
driver.get(url)
soup = BeautifulSoup( driver.page_source, 'html.parser' )
if soup.select_one(css_selector):
print('match on', url)

Related

Ubuntu 22.04 installed gnome-session-flashback not able to add new menu item

Environment:
Windows 10 Home Edition host
VirtualBox running Ubuntu 22.04 Desktop
In previous versions of Ubuntu installed gnome-session-flashback and have been able to edit menu including adding new menu items
Upon fresh installation of Ubuntu 22.04
Items could be removed/moved within a category &etc.
However "New Item" would bring up dialog box but would not process item to add.
Gnome 42 Alacarte Error AttributeError: 'LauncherEditor' object has no attribute 'icon_file'
This error just indicates that you need to choose an icon file image for the command and it will save Menu Item with no error you do not need to change the code to prior version .
Ran menu edit in terminal with privileges:
$sudo alacarte
watching output/stack trace upon submitting 'add item' results:
AttributeError: 'LauncherEditor' object has no attribute 'icon_file'
Checked file/line # in stack trace. (file: usr/share/alacarte/Alacarte/ItemEditor.py) Compared this to working version in Ubuntu 20.04
lines of code: 20.04 --> 269 vs 22.04 --> 293
Backed up 22.04 version of ItemEditor.py
Replaced it with 20.04 version of ItemEditor.py
Menu edits including add item working.
Here is the ItemEditor.py 20.04 version:
# -*- coding: utf-8 -*-
# Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
# Copyright (C) 2013 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gettext
import os
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, GObject, Gtk
from Alacarte import config, util
_ = gettext.gettext
EXTENSIONS = (".png", ".xpm", ".svg")
def try_icon_name(filename):
# Detect if the user picked an icon, and make
# it into an icon name.
if not filename.endswith(EXTENSIONS):
return filename
theme = Gtk.IconTheme.get_default()
resolved_path = None
for path in theme.get_search_path():
if filename.startswith(path):
resolved_path = filename[len(path):].lstrip(os.sep)
break
if resolved_path is None:
return filename
parts = resolved_path.split(os.sep)
# icon-theme/size/category/icon
if len(parts) != 4:
return filename
icon_name = parts[3]
# strip extension
return icon_name[:-4]
def get_icon_string(image):
filename = image.props.file
if filename is not None:
return try_icon_name(filename)
return image.props.icon_name
def strip_extensions(icon):
if icon.endswith(EXTENSIONS):
return icon[:-4]
else:
return icon
def set_icon_string(image, icon):
if GLib.path_is_absolute(icon):
image.props.file = icon
else:
image.props.icon_name = strip_extensions(icon)
DESKTOP_GROUP = GLib.KEY_FILE_DESKTOP_GROUP
# XXX - replace with a better UI eventually
class IconPicker(object):
def __init__(self, dialog, button, image):
self.dialog = dialog
self.button = button
self.button.connect('clicked', self.pick_icon)
self.image = image
def pick_icon(self, button):
chooser = Gtk.FileChooserDialog(title=_("Choose an icon"),
parent=self.dialog,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
response = chooser.run()
if response == Gtk.ResponseType.ACCEPT:
self.image.props.file = chooser.get_filename()
chooser.destroy()
class ItemEditor(GObject.GObject):
ui_file = None
__gsignals__ = {
'response': (GObject.SIGNAL_RUN_FIRST, None, (bool,))
}
def __init__(self, parent, item_path):
GObject.GObject.__init__(self)
self.builder = Gtk.Builder()
self.builder.add_from_file(os.path.join(config.pkgdatadir, self.ui_file))
self.dialog = self.builder.get_object('editor')
self.dialog.set_transient_for(parent)
self.dialog.connect('response', self.on_response)
self.build_ui()
self.item_path = item_path
self.load()
self.resync_validity()
def build_ui(self):
raise NotImplementedError()
def get_keyfile_edits(self):
raise NotImplementedError()
def set_text(self, ctl, name):
try:
val = self.keyfile.get_string(DESKTOP_GROUP, name)
except GLib.GError:
pass
else:
self.builder.get_object(ctl).set_text(val)
def set_check(self, ctl, name):
try:
val = self.keyfile.get_boolean(DESKTOP_GROUP, name)
except GLib.GError:
pass
else:
self.builder.get_object(ctl).set_active(val)
def set_icon(self, ctl, name):
try:
val = self.keyfile.get_string(DESKTOP_GROUP, name)
except GLib.GError:
pass
else:
set_icon_string(self.builder.get_object(ctl), val)
def load(self):
self.keyfile = GLib.KeyFile()
try:
self.keyfile.load_from_file(self.item_path, util.KEY_FILE_FLAGS)
except GLib.GError:
pass
def save(self):
util.fillKeyFile(self.keyfile, self.get_keyfile_edits())
contents, length = self.keyfile.to_data()
with open(self.item_path, 'w') as f:
f.write(contents)
def run(self):
self.dialog.present()
def on_response(self, dialog, response):
if response == Gtk.ResponseType.OK:
self.save()
self.dialog.destroy()
self.emit('response', response == Gtk.ResponseType.OK)
class LauncherEditor(ItemEditor):
ui_file = 'launcher-editor.ui'
def build_ui(self):
self.icon_picker = IconPicker(self.dialog,
self.builder.get_object('icon-button'),
self.builder.get_object('icon-image'))
self.builder.get_object('exec-browse').connect('clicked', self.pick_exec)
self.builder.get_object('name-entry').connect('changed', self.resync_validity)
self.builder.get_object('exec-entry').connect('changed', self.resync_validity)
def exec_line_is_valid(self, exec_text):
try:
success, parsed = GLib.shell_parse_argv(exec_text)
# Make sure program (first part of the command) is in the path
command = parsed[0]
return (GLib.find_program_in_path(command) is not None)
except GLib.GError:
return False
def resync_validity(self, *args):
name_text = self.builder.get_object('name-entry').get_text()
exec_text = self.builder.get_object('exec-entry').get_text()
valid = (name_text != "" and self.exec_line_is_valid(exec_text))
self.builder.get_object('ok').set_sensitive(valid)
def load(self):
super(LauncherEditor, self).load()
self.set_text('name-entry', "Name")
self.set_text('exec-entry', "Exec")
self.set_text('comment-entry', "Comment")
self.set_check('terminal-check', "Terminal")
self.set_icon('icon-image', "Icon")
def get_keyfile_edits(self):
return dict(Name=self.builder.get_object('name-entry').get_text(),
Exec=self.builder.get_object('exec-entry').get_text(),
Comment=self.builder.get_object('comment-entry').get_text(),
Terminal=self.builder.get_object('terminal-check').get_active(),
Icon=get_icon_string(self.builder.get_object('icon-image')),
Type="Application")
def pick_exec(self, button):
chooser = Gtk.FileChooserDialog(title=_("Choose a command"),
parent=self.dialog,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
response = chooser.run()
if response == Gtk.ResponseType.ACCEPT:
self.builder.get_object('exec-entry').set_text(chooser.get_filename())
chooser.destroy()
class DirectoryEditor(ItemEditor):
ui_file = 'directory-editor.ui'
def build_ui(self):
self.icon_picker = IconPicker(self.dialog,
self.builder.get_object('icon-button'),
self.builder.get_object('icon-image'))
self.builder.get_object('name-entry').connect('changed', self.resync_validity)
def resync_validity(self, *args):
name_text = self.builder.get_object('name-entry').get_text()
valid = (name_text != "")
self.builder.get_object('ok').set_sensitive(valid)
def load(self):
super(DirectoryEditor, self).load()
self.set_text('name-entry', "Name")
self.set_text('comment-entry', "Comment")
self.set_icon('icon-image', "Icon")
def get_keyfile_edits(self):
return dict(Name=self.builder.get_object('name-entry').get_text(),
Comment=self.builder.get_object('comment-entry').get_text(),
Icon=get_icon_string(self.builder.get_object('icon-image')),
Type="Directory")
def test_editor(path):
if path.endswith('.directory'):
return DirectoryEditor(path)
elif path.endswith('.desktop'):
return LauncherEditor(path)
else:
raise ValueError("Invalid filename, %r" % (path,))
def test():
import sys
Gtk.Window.set_default_icon_name('alacarte')
editor = test_editor(sys.argv[1])
editor.dialog.connect('destroy', Gtk.main_quit)
editor.run()
Gtk.main()
if __name__ == "__main__":
test()

How to download JIRA attachment files with Python

I want to download attachment files of an issue in JIRA Python.
I use jira python lib ,you can use pip install JIRA
# -- coding: UTF-8 --
from jira import JIRA
import requests
url = 'https://jira.1234.com'
jira = JIRA(server=url, basic_auth=('admin', 'password'))
attachment=jira.attachment(12345) #12345 is attachment_key
image = attachment.get()
with open("Image.png", 'wb') as f:
f.write(image)
JIRA exposes its REST services and through that and some python you can download any attachment.
It worked for me like this (you'll need to adjust the variables):
#!/usr/bin/python
# miguel ortiz
# Requests module: http://docs.python-requests.org/en/latest/
# Documentation: <url>
#----------------------------------------------------------------Modules
import sys
import csv, json
import requests
#----------------------------------------------------------------Variables
myTicket= sys.argv[1] # Your ticket: ABC-123
user = 'miguel' # JIRA user
pasw = 'password' # JIRA password
jiraURL = 'https://yourinstance.jira.com/rest/api/latest/issue/'
fileName = 'my_attached_file' # In this case we'll be looking for a specific file in the attachments
attachment_final_url="" # To validate if there are or not attachments
def main() :
print '\n\n [ You are checking ticket: ' + myTicket+ ' ]\n'
# Request Json from JIRA API
r = requests.get(jiraURL+myTicket, auth=(user, pasw),timeout=5)
# status of the request
rstatus = r.status_code
# If the status isn't 200 we leave
if not rstatus == 200 :
print 'Error accesing JIRA:' + str(rstatus)
exit()
else:
data = r.json()
if not data['fields']['attachment'] :
status_attachment = 'ERROR: Nothing attached, attach a file named: ' + fileName
attachment_final_url=""
else:
for i in data['fields']['attachment'] :
if i['filename'] == fileName :
attachment_final_url = i['content']
status_attachment_name = 'OK: The desired attachment exists: ' + fileName
attachment_name = False
attachment_amount = False
attachment_files = False
break
else :
attachment_files = False
status_attachment_name = + 'ERROR: None of the files has the desired name '
attachment_final_url=""
attachment_name = True
attachment_amount = True
continue
if attachment_final_url != "" :
r = requests.get(attachment_final_url, auth=(user, pasw), stream=True)
with open(fileName, "wb") as f:
f.write(r.content.decode('iso-8859-1').encode('utf8'))
f.close()
else:
print status_attachment
if __name__ == "__main__" :
main()
If you do not understand the code I've detailed it better in my blog.
EDIT: Be careful, in JIRA you can add many files with the same name.

How to get the Tor ExitNode IP with Python and Stem

I'm trying to get the external IP that Tor uses, as mentioned here. When using something like myip.dnsomatic.com, this is very slow. I tried what was suggested in the aforementioned link (python + stem to control tor through the control port), but all you get is circuit's IPs with no assurance of which one is the one on the exitnode, and, sometimes the real IP is not even among the results.
Any help would be appreciated.
Also, from here, at the bottom, Amine suggests a way to renew the identity in Tor. There is an instruction, controller.get_newnym_wait(), which he uses to wait until the new connection is ready (controller is from Control in steam.control), isn't there any thing like that in Steam (sorry, I checked and double/triple checked and couldn't find nothing) that tells you that Tor is changing its identity?
You can get the exit node ip without calling a geoip site.
This is however on a different stackexchange site here - https://tor.stackexchange.com/questions/3253/how-do-i-trap-circuit-id-none-errors-in-the-stem-script-exit-used-py
As posted by #mirimir his code below essentially attaches a stream event listener function, which is then used to get the circuit id, circuit fingerprint, then finally the exit ip address -
#!/usr/bin/python
import functools
import time
from stem import StreamStatus
from stem.control import EventType, Controller
def main():
print "Tracking requests for tor exits. Press 'enter' to end."
print
with Controller.from_port() as controller:
controller.authenticate()
stream_listener = functools.partial(stream_event, controller)
controller.add_event_listener(stream_listener, EventType.STREAM)
raw_input() # wait for user to press enter
def stream_event(controller, event):
if event.status == StreamStatus.SUCCEEDED and event.circ_id:
circ = controller.get_circuit(event.circ_id)
exit_fingerprint = circ.path[-1][0]
exit_relay = controller.get_network_status(exit_fingerprint)
t = time.localtime()
print "datetime|%d-%02d-%02d %02d:%02d:%02d % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
print "website|%s" % (event.target)
print "exitip|%s" % (exit_relay.address)
print "exitport|%i" % (exit_relay.or_port)
print "fingerprint|%s" % exit_relay.fingerprint
print "nickname|%s" % exit_relay.nickname
print "locale|%s" % controller.get_info("ip-to-country/%s" % exit_relay.address, 'unknown')
print
You can use this code for check current IP (change SOCKS_PORT value to yours):
import re
import stem.process
import requesocks
SOCKS_PORT = 9053
tor_process = stem.process.launch_tor()
proxy_address = 'socks5://127.0.0.1:{}'.format(SOCKS_PORT)
proxies = {
'http': proxy_address,
'https': proxy_address
}
response = requesocks.get("http://httpbin.org/ip", proxies=proxies)
print re.findall(r'[\d.-]+', response.text)[0]
tor_process.kill()
If you want to use socks you should do:
pip install requests[socks]
Then you can do:
import requests
import json
import stem.process
import stem
SOCKS_PORT = "9999"
tor = stem.process.launch_tor_with_config(
config={
'SocksPort': SOCKS_PORT,
},
tor_cmd= 'absolute_path/to/tor.exe',
)
r = requests.Session()
proxies = {
'http': 'socks5://localhost:' + SOCKS_PORT,
'https': 'socks5://localhost:' + SOCKS_PORT
}
response = r.get("http://httpbin.org/ip", proxies=proxies)
self.current_ip = response.json()['origin']

Create a portal_user_catalog and have it used (Plone)

I'm creating a fork of my Plone site (which has not been forked for a long time). This site has a special catalog object for user profiles (a special Archetypes-based object type) which is called portal_user_catalog:
$ bin/instance debug
>>> portal = app.Plone
>>> print [d for d in portal.objectMap() if d['meta_type'] == 'Plone Catalog Tool']
[{'meta_type': 'Plone Catalog Tool', 'id': 'portal_catalog'},
{'meta_type': 'Plone Catalog Tool', 'id': 'portal_user_catalog'}]
This looks reasonable because the user profiles don't have most of the indexes of the "normal" objects, but have a small set of own indexes.
Since I found no way how to create this object from scratch, I exported it from the old site (as portal_user_catalog.zexp) and imported it in the new site. This seemed to work, but I can't add objects to the imported catalog, not even by explicitly calling the catalog_object method. Instead, the user profiles are added to the standard portal_catalog.
Now I found a module in my product which seems to serve the purpose (Products/myproduct/exportimport/catalog.py):
"""Catalog tool setup handlers.
$Id: catalog.py 77004 2007-06-24 08:57:54Z yuppie $
"""
from Products.GenericSetup.utils import exportObjects
from Products.GenericSetup.utils import importObjects
from Products.CMFCore.utils import getToolByName
from zope.component import queryMultiAdapter
from Products.GenericSetup.interfaces import IBody
def importCatalogTool(context):
"""Import catalog tool.
"""
site = context.getSite()
obj = getToolByName(site, 'portal_user_catalog')
parent_path=''
if obj and not obj():
importer = queryMultiAdapter((obj, context), IBody)
path = '%s%s' % (parent_path, obj.getId().replace(' ', '_'))
__traceback_info__ = path
print [importer]
if importer:
print importer.name
if importer.name:
path = '%s%s' % (parent_path, 'usercatalog')
print path
filename = '%s%s' % (path, importer.suffix)
print filename
body = context.readDataFile(filename)
if body is not None:
importer.filename = filename # for error reporting
importer.body = body
if getattr(obj, 'objectValues', False):
for sub in obj.objectValues():
importObjects(sub, path+'/', context)
def exportCatalogTool(context):
"""Export catalog tool.
"""
site = context.getSite()
obj = getToolByName(site, 'portal_user_catalog', None)
if tool is None:
logger = context.getLogger('catalog')
logger.info('Nothing to export.')
return
parent_path=''
exporter = queryMultiAdapter((obj, context), IBody)
path = '%s%s' % (parent_path, obj.getId().replace(' ', '_'))
if exporter:
if exporter.name:
path = '%s%s' % (parent_path, 'usercatalog')
filename = '%s%s' % (path, exporter.suffix)
body = exporter.body
if body is not None:
context.writeDataFile(filename, body, exporter.mime_type)
if getattr(obj, 'objectValues', False):
for sub in obj.objectValues():
exportObjects(sub, path+'/', context)
I tried to use it, but I have no idea how it is supposed to be done;
I can't call it TTW (should I try to publish the methods?!).
I tried it in a debug session:
$ bin/instance debug
>>> portal = app.Plone
>>> from Products.myproduct.exportimport.catalog import exportCatalogTool
>>> exportCatalogTool(portal)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../Products/myproduct/exportimport/catalog.py", line 58, in exportCatalogTool
site = context.getSite()
AttributeError: getSite
So, if this is the way to go, it looks like I need a "real" context.
Update: To get this context, I tried an External Method:
# -*- coding: utf-8 -*-
from Products.myproduct.exportimport.catalog import exportCatalogTool
from pdb import set_trace
def p(dt, dd):
print '%-16s%s' % (dt+':', dd)
def main(self):
"""
Export the portal_user_catalog
"""
g = globals()
print '#' * 79
for a in ('__package__', '__module__'):
if a in g:
p(a, g[a])
p('self', self)
set_trace()
exportCatalogTool(self)
However, wenn I called it, I got the same <PloneSite at /Plone> object as the argument to the main function, which didn't have the getSite attribute. Perhaps my site doesn't call such External Methods correctly?
Or would I need to mention this module somehow in my configure.zcml, but how? I searched my directory tree (especially below Products/myproduct/profiles) for exportimport, the module name, and several other strings, but I couldn't find anything; perhaps there has been an integration once but was broken ...
So how do I make this portal_user_catalog work?
Thank you!
Update: Another debug session suggests the source of the problem to be some transaction matter:
>>> portal = app.Plone
>>> puc = portal.portal_user_catalog
>>> puc._catalog()
[]
>>> profiles_folder = portal.some_folder_with_profiles
>>> for o in profiles_folder.objectValues():
... puc.catalog_object(o)
...
>>> puc._catalog()
[<Products.ZCatalog.Catalog.mybrains object at 0x69ff8d8>, ...]
This population of the portal_user_catalog doesn't persist; after termination of the debug session and starting fg, the brains are gone.
It looks like the problem was indeed related with transactions.
I had
import transaction
...
class Browser(BrowserView):
...
def processNewUser(self):
....
transaction.commit()
before, but apparently this was not good enough (and/or perhaps not done correctly).
Now I start the transaction explicitly with transaction.begin(), save intermediate results with transaction.savepoint(), abort the transaction explicitly with transaction.abort() in case of errors (try / except), and have exactly one transaction.commit() at the end, in the case of success. Everything seems to work.
Of course, Plone still doesn't take this non-standard catalog into account; when I "clear and rebuild" it, it is empty afterwards. But for my application it works well enough.

Development Mode For uWSGI/Pylons (Reload new code)

I have a setup such that an nginx server passes control off to uWsgi, which launches a pylons app using the following in my xml configuration file:
<ini-paste>...</ini-paste>
Everything is working nicely, and I was able to set it to debug mode using the following in the associated ini file, like:
debug = true
Except debug mode only prints out errors, and doesn't reload the code everytime a file has been touched. If I was running directly through paste, I could use the --reload option, but going through uWsgi complicates things.
Does anybody know of a way to tell uWsgi to tell paste to set the --reload option, or to do this directly in the paste .ini file?
I used something like the following code to solve this, the monitorFiles(...) method is called on application initialization, and it monitors the files, sending the TERM signal when it sees a change.
I'd still much prefer a solution using paster's --reload argument, as I imagine this solution has bugs:
import os
import time
import signal
from deepthought.system import deployment
from multiprocessing.process import Process
def monitorFiles():
if deployment.getDeployment().dev and not FileMonitor.isRunning:
monitor = FileMonitor(os.getpid())
try: monitor.start()
except: print "Something went wrong..."
class FileMonitor(Process):
isRunning = False
def __init__(self, masterPid):
self.updates = {}
self.rootDir = deployment.rootDir() + "/src/python"
self.skip = len(self.rootDir)
self.masterPid = masterPid
FileMonitor.isRunning = True
Process.__init__(self)
def run(self):
while True:
self._loop()
time.sleep(5)
def _loop(self):
for root, _, files in os.walk(self.rootDir):
for file in files:
if file.endswith(".py"):
self._monitorFile(root, file)
def _monitorFile(self, root, file):
mtime = os.path.getmtime("%s/%s" % (root, file))
moduleName = "%s/%s" % (root[self.skip+1:], file[:-3])
moduleName = moduleName.replace("/",".")
if not moduleName in self.updates:
self.updates[moduleName] = mtime
elif self.updates[moduleName] < mtime:
print "Change detected in %s" % moduleName
self._restartWorker()
self.updates[moduleName] = mtime
def _restartWorker(self):
os.kill(self.masterPid, signal.SIGTERM)
Use the signal framework in 0.9.7 tree
http://projects.unbit.it/uwsgi/wiki/SignalFramework
An example of auto-reloading:
import uwsgi
uwsgi.register_signal(1, "", uwsgi.reload)
uwsgi.add_file_monitor(1, 'myfile.py')
def application(env, start_response):
...

Resources