Compare commits

...

3 commits

Author SHA1 Message Date
26faed014f Standardize Bot class names 2014-07-17 15:27:28 +02:00
f9970cba42 Add build system 2014-07-17 14:52:13 +02:00
35ae6b6245 Introducing nemubot v4 directories architecture 2014-07-17 14:45:31 +02:00
29 changed files with 252 additions and 134 deletions

2
.gitignore vendored
View file

@ -3,4 +3,6 @@
TAGS
*.py[cod]
__pycache__
build/
datas/
dist/

7
.travis.yml Normal file
View file

@ -0,0 +1,7 @@
language: python
python:
- 3.2
- 3.3
- 3.4
install: pip install -r requirements.txt
script: pip install .

View file

@ -1,7 +1,21 @@
# *nemubot*
# nemubot
An extremely modulable IRC bot, built around XML configuration files!
A smart and modulable IM bot!
## Usage
TODO
## Documentation
Have a look to the wiki at https://github.com/nemunaire/nemubot/wiki
## Building
TODO
## License
This software is copyright (c) 2014 by nemunaire.
This is free software; you can redistribute it and/or modify it under the same terms as GNU Affero General Public Licence v3.

View file

@ -1,8 +1,8 @@
#!/usr/bin/python3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,14 +22,14 @@ import os
import imp
import traceback
import bot
import prompt
from prompt.builtins import load_file
import importer
import nemubot
from nemubot import prompt
from nemubot.prompt.builtins import load_file
from nemubot import importer
if __name__ == "__main__":
# Create bot context
context = bot.Bot(0, "FIXME")
context = nemubot.Bot()
# Load the prompt
prmpt = prompt.Prompt()
@ -50,7 +50,7 @@ if __name__ == "__main__":
else:
load_file(arg, context)
print ("Nemubot v%s ready, my PID is %i!" % (context.version_txt,
print ("Nemubot v%s ready, my PID is %i!" % (nemubot.__version__,
os.getpid()))
while prmpt.run(context):
try:
@ -63,7 +63,7 @@ if __name__ == "__main__":
# Reload all other modules
bot.reload()
print ("\033[1;32mContext reloaded\033[0m, now in Nemubot %s" %
context.version_txt)
nemubot.__version__)
except:
print ("\033[1;31mUnable to reload the prompt due to errors.\033[0"
"m Fix them before trying to reload the prompt.")

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -25,8 +25,8 @@ import time
import threading
import traceback
import message
import server
import nemubot.message
from nemubot import server
#Store all used ports
PORTS = list()

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -23,12 +23,12 @@ import socket
import threading
import traceback
from channel import Channel
from DCC import DCC
from hooks import Hook
import message
import server
import xmlparser
from nemubot.channel import Channel
from nemubot.DCC import DCC
from nemubot.hooks import Hook
import nemubot.message
from nemubot import server
import nemubot.xmlparser
class IRCServer(server.Server):
"""Class to interact with an IRC server"""

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -16,43 +16,47 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
from datetime import timedelta
from datetime import datetime, timedelta
from ipaddress import ip_address
import logging
from queue import Queue
import threading
import time
import re
import uuid
import consumer
import event
import hooks
from networkbot import NetworkBot
from IRCServer import IRCServer
from DCC import DCC
import response
__version__ = '4.0.dev0'
__author__ = 'nemunaire'
ID_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
from nemubot import consumer
from nemubot import event
from nemubot import hooks
from nemubot.networkbot import NetworkBot
from nemubot.IRCServer import IRCServer
from nemubot.DCC import DCC
from nemubot import response
class Bot:
def __init__(self, ip, realname, mp=list()):
# Bot general informations
self.version = 3.3
self.version_txt = "3.3"
# Save various informations
self.ip = ip
self.realname = realname
self.ctcp_capabilities = dict()
self.init_ctcp_capabilities()
"""Class containing the bot context and ensuring key goals"""
def __init__(self, ip="127.0.0.1", modules_paths=list(), data_path="./datas/"):
"""Initialize the bot context
Keyword arguments:
ip -- The external IP of the bot (default: 127.0.0.1)
modules_paths -- Paths to all directories where looking for module
data_path -- Path to directory where store bot context data
"""
# External IP for accessing this bot
self.ip = ip_address(ip)
# Context paths
self.modules_paths = modules_paths
self.data_path = data_path
# Keep global context: servers and modules
self.servers = dict()
self.modules = dict()
# Context paths
self.modules_path = mp
self.datas_path = './datas/'
# Events
self.events = list()
self.event_timer = None
@ -62,13 +66,16 @@ class Bot:
# Other known bots, making a bots network
self.network = dict()
self.hooks_cache = dict()
self._hooks_cache = dict()
# Messages to be treated
self.cnsr_queue = Queue()
self.cnsr_thrd = list()
self.cnsr_thrd_size = -1
# Stop the class thread
self.stop = False
self.hooks.add_hook("irc_hook",
hooks.Hook(self.treat_prvmsg, "PRIVMSG"),
self)
@ -80,13 +87,13 @@ class Bot:
self.ctcp_capabilities["CLIENTINFO"] = self._ctcp_clientinfo
self.ctcp_capabilities["DCC"] = self._ctcp_dcc
self.ctcp_capabilities["NEMUBOT"] = lambda srv, msg: _ctcp_response(
msg.sender, "NEMUBOT %f" % self.version)
msg.sender, "NEMUBOT %f" % __version__)
self.ctcp_capabilities["TIME"] = lambda srv, msg: _ctcp_response(
msg.sender, "TIME %s" % (datetime.now()))
self.ctcp_capabilities["USERINFO"] = lambda srv, msg: _ctcp_response(
msg.sender, "USERINFO %s" % self.realname)
self.ctcp_capabilities["VERSION"] = lambda srv, msg: _ctcp_response(
msg.sender, "VERSION nemubot v%s" % self.version_txt)
msg.sender, "VERSION nemubot v%s" % __version__)
def _ctcp_clientinfo(self, srv, msg):
"""Response to CLIENTINFO CTCP message"""
@ -104,6 +111,8 @@ class Bot:
print ("DCC: unable to connect to %s:%s" % (ip, msg.cmds[4]))
# Events methods
def add_event(self, evt, eid=None, module_src=None):
"""Register an event and return its identifiant for futur update"""
if eid is None:
@ -125,7 +134,7 @@ class Bot:
break
self.events.insert(i + 1, evt)
if i == -1:
self.update_timer()
self._update_event_timer()
if len(self.events) <= 0 or self.events[i+1] != evt:
return None
@ -138,7 +147,7 @@ class Bot:
"""Find and remove an event from list"""
if len(self.events) > 0 and id == self.events[0].id:
self.events.remove(self.events[0])
self.update_timer()
self._update_event_timer()
if module_src is not None:
module_src.REGISTERED_EVENTS.remove(evt.id)
return True
@ -152,7 +161,7 @@ class Bot:
return True
return False
def update_timer(self):
def _update_event_timer(self):
"""Relaunch the timer to end with the closest event"""
# Reset the timer if this is the first item
if self.event_timer is not None:
@ -180,9 +189,11 @@ class Bot:
self.cnsr_queue.put_nowait(consumer.EventConsumer(evt))
self.update_consumers()
self.update_timer()
self._update_event_timer()
# Server methods
def addServer(self, node, nick, owner, realname, ssl=False):
"""Add a new server to the context"""
srv = IRCServer(node, nick, owner, realname, ssl)
@ -199,6 +210,8 @@ class Bot:
return False
# Modules methods
def add_module(self, module):
"""Add a module to the context, if already exists, unload the
old one before"""
@ -218,8 +231,8 @@ class Bot:
if path[len(path)-1] != "/":
path = path + "/"
if path not in self.modules_path:
self.modules_path.append(path)
if path not in self.modules_paths:
self.modules_paths.append(path)
return True
return False
@ -243,6 +256,9 @@ class Bot:
return True
return False
# Consumers methods
def update_consumers(self):
"""Launch new consumer thread if necessary"""
if self.cnsr_queue.qsize() > self.cnsr_thrd_size:
@ -292,14 +308,14 @@ class Bot:
# Hooks cache
def create_cache(self, name):
if name not in self.hooks_cache:
if name not in self._hooks_cache:
if isinstance(self.hooks.__dict__[name], list):
self.hooks_cache[name] = list()
self._hooks_cache[name] = list()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
tpl = (h, 0, self.hooks.__dict__[name], self.hooks.bot)
self.hooks_cache[name].append(tpl)
self._hooks_cache[name].append(tpl)
# Now, add extermal hooks
level = 0
@ -309,17 +325,17 @@ class Bot:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name].append((h, level + 1,
if h not in self._hooks_cache[name]:
self._hooks_cache[name].append((h, level + 1,
self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot))
level += 1
elif isinstance(self.hooks.__dict__[name], dict):
self.hooks_cache[name] = dict()
self._hooks_cache[name] = dict()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
self.hooks_cache[name][h] = (self.hooks.__dict__[name][h], 0,
self._hooks_cache[name][h] = (self.hooks.__dict__[name][h], 0,
self.hooks.__dict__[name],
self.hooks.bot)
@ -331,14 +347,14 @@ class Bot:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name][h] = (self.network[ext].hooks[level].__dict__[name][h], level + 1, self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot)
if h not in self._hooks_cache[name]:
self._hooks_cache[name][h] = (self.network[ext].hooks[level].__dict__[name][h], level + 1, self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot)
level += 1
else:
raise Exception(name + " hook type unrecognized")
return self.hooks_cache[name]
return self._hooks_cache[name]
# Treatment
@ -603,7 +619,7 @@ def _help_msg(sndr, modules, cmd):
return res
def hotswap(bak):
return Bot(bak.servers, bak.modules, bak.modules_path)
return Bot(bak.servers, bak.modules, bak.modules_paths)
def reload():
import imp

View file

@ -1,7 +1,7 @@
# coding=utf-8
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,11 +22,10 @@ import threading
import traceback
import sys
import bot
from DCC import DCC
from message import Message
import response
import server
from nemubot.DCC import DCC
from nemubot.message import Message
from nemubot import response
from nemubot import server
class MessageConsumer:
"""Store a message before treating"""

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# coding=utf-8
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from response import Response
from nemubot.response import Response
class IRCException(Exception):

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -18,8 +18,8 @@
import re
from response import Response
from exception import IRCException
from nemubot.response import Response
from nemubot.exception import IRCException
class MessagesHook:
def __init__(self, context, bot):
@ -56,8 +56,8 @@ class MessagesHook:
"add_hook function, please fix it in order to be "
"compatible with unload feature")
if store in self.context.hooks_cache:
del self.context.hooks_cache[store]
if store in self.context._hooks_cache:
del self.context._hooks_cache[store]
if not hasattr(self, store):
print ("\033[1;35mWarning:\033[0m unrecognized hook store")
@ -143,8 +143,8 @@ class MessagesHook:
def del_hook(self, store, hook, module_src=None):
"""Remove a registered hook from a given store"""
if store in self.context.hooks_cache:
del self.context.hooks_cache[store]
if store in self.context._hooks_cache:
del self.context._hooks_cache[store]
if not hasattr(self, store):
print ("Warning: unrecognized hook store type")

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -16,17 +16,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from distutils.version import StrictVersion
from importlib.abc import Finder
from importlib.abc import SourceLoader
import imp
import os
import sys
import event
import exception
from hooks import Hook
import response
import xmlparser
import nemubot
from nemubot import event
from nemubot import exception
from nemubot.hooks import Hook
from nemubot import response
from nemubot import xmlparser
class ModuleFinder(Finder):
def __init__(self, context, prompt):
@ -37,7 +39,7 @@ class ModuleFinder(Finder):
#print ("looking for", fullname, "in", path)
# Search only for new nemubot modules (packages init)
if path is None:
for mpath in self.context.modules_path:
for mpath in self.context.modules_paths:
#print ("looking for", fullname, "in", mpath)
if os.path.isfile(mpath + fullname + ".xml"):
return ModuleLoader(self.context, self.prompt, fullname,
@ -137,7 +139,7 @@ class ModuleLoader(SourceLoader):
if not hasattr(module, "nemubotversion"):
raise ImportError("Module `%s' is not a nemubot module."%self.name)
# Check module version
if module.nemubotversion != self.context.version:
if StrictVersion(module.nemubotversion) != StrictVersion(nemubot.__version__):
raise ImportError("Module `%s' is not compatible with this "
"version." % self.name)

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -21,10 +21,10 @@ import re
import shlex
import time
import credits
from credits import Credits
from response import Response
import xmlparser
import nemubot.credits
from nemubot.credits import Credits
from nemubot.response import Response
import nemubot.xmlparser
CREDITS = {}
filename = ""

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,9 @@ import shlex
import urllib.parse
import zlib
from DCC import DCC
import hooks
from response import Response
from nemubot.DCC import DCC
import nemubot.hooks
from nemubot.response import Response
class NetworkBot:
def __init__(self, context, srv, dest, dcc=None):

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -17,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import xmlparser
from nemubot import xmlparser
def end(toks, context, prompt):
"""Quit the prompt for reload or exit"""

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -165,7 +165,7 @@ class Response:
self.elt = 0
return msg
import hooks
import nemubot.hooks
class Hook:
def __init__(self, TYPE, call, name=None, data=None, regexp=None,
channels=list(), server=None, end=None, call_end=None,

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# coding=utf-8
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# coding=utf-8
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -19,9 +19,9 @@
import traceback
import sys
from networkbot import NetworkBot
from nemubot.networkbot import NetworkBot
nemubotversion = 3.3
nemubotversion = 4.0
NODATA = True
def getserver(toks, context, prompt):

0
requirements.txt Normal file
View file

77
setup.py Normal file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env python3
#-*- encoding: utf-8 -*-
import os
import re
from glob import glob
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
with open(os.path.join(os.path.dirname(__file__),
'lib',
'__init__.py')) as f:
version = re.search("__version__ = '([^']+)'", f.read()).group(1)
with open('requirements.txt', 'r') as f:
requires = [x.strip() for x in f if x.strip()]
#with open('test-requirements.txt', 'r') as f:
# test_requires = [x.strip() for x in f if x.strip()]
dirs = os.listdir("./modules/")
data_files = []
for i in dirs:
data_files.append(("nemubot/modules", glob('./modules/' + i + '/*')))
setup(
name="nemubot",
version=version,
description="A smart and modulable IM bot!",
long_description=open('README.md').read(),
author='nemunaire',
author_email='nemunaire@nemunai.re',
url='https://github.com/nemunaire/nemubot',
license='AGPLv3',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Environment :: Console',
'Topic :: Communications :: Chat :: Internet Relay Chat',
'Intended Audience :: Information Technology',
'License :: OSI Approved :: GNU Affero General Public License v3',
'Operating System :: POSIX',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
],
keywords='bot irc',
install_requires = requires,
package_dir={ 'nemubot': 'lib' },
packages=[
'nemubot',
'nemubot.prompt',
'nemubot.tools',
'nemubot.xmlparser',
],
scripts=[
'bin/nemubot',
# 'bin/module_tester',
],
# data_files=data_files,
)