Commit bd5a60ff7ac95885ce585668bfb569a73cc65e47

Authored by Etienne Pallier
1 parent 5a3ed30a
Exists in dev

cleanup

install/REQUIREMENTS_36.txt deleted
... ... @@ -1,36 +0,0 @@
1   -anyjson==0.3.3
2   -DateTime==4.2
3   -Django==2.0.5
4   -django-admin-tools==0.8.1
5   -django-bootstrap3==10.0.1
6   -django-debug-toolbar==1.9.1
7   -django-extensions==2.0.7
8   -django-suit==0.2.26
9   -django-test-without-migrations==0.6
10   -#gunicorn==19.8.1
11   -iso8601==0.1.12
12   -jdcal==1.4
13   -#lxml==3.8.0 (windows version)
14   -lxml==4.3.0
15   -mysqlclient==1.3.12
16   -#pluggy==0.6.0
17   -#pluggy>=0.7
18   -pluggy==0.8.1
19   -py==1.5.3
20   -pytz==2018.4
21   -requests==2.18.4
22   -six==1.11.0
23   -sqlparse==0.2.4
24   -Twisted==18.4.0
25   -#voevent-parse==1.0.2 (windows version)
26   -voevent-parse==1.0.3
27   -zope.interface==4.5.0
28   -
29   -# For Celery:
30   -##celery==3.1.23
31   -##flower==0.9.2
32   -##amqp==1.4.9
33   -##amqplib==1.0.2
34   -##billiard==3.3.0.23
35   -##kombu==3.0.37
36   -##django-celery==3.1.17
install/REQUIREMENTS_37.txt deleted
... ... @@ -1,33 +0,0 @@
1   -anyjson==0.3.3
2   -DateTime==4.2
3   -Django==2.0.5
4   -django-admin-tools==0.8.1
5   -django-bootstrap3==10.0.1
6   -django-debug-toolbar==1.9.1
7   -django-extensions==2.0.7
8   -django-suit==0.2.26
9   -django-test-without-migrations==0.6
10   -#gunicorn==19.8.1
11   -iso8601==0.1.12
12   -jdcal==1.4
13   -lxml==4.3.0
14   -mysqlclient==1.3.12
15   -#pluggy>=0.7
16   -pluggy==0.8.1
17   -py==1.5.3
18   -pytz==2018.4
19   -requests==2.18.4
20   -six==1.11.0
21   -sqlparse==0.2.4
22   -Twisted==18.4.0
23   -voevent-parse==1.0.3
24   -zope.interface==4.5.0
25   -
26   -# For Celery:
27   -##celery==3.1.23
28   -##flower==0.9.2
29   -##amqp==1.4.9
30   -##amqplib==1.0.2
31   -##billiard==3.3.0.23
32   -##kombu==3.0.37
33   -##django-celery==3.1.17
install/REQUIREMENTS_freezed_37.txt deleted
... ... @@ -1,34 +0,0 @@
1   -anyjson==0.3.3
2   -astropy==3.1.1
3   -attrs==18.2.0
4   -Automat==0.7.0
5   -certifi==2018.11.29
6   -chardet==3.0.4
7   -constantly==15.1.0
8   -DateTime==4.2
9   -Django==2.0.5
10   -django-admin-tools==0.8.1
11   -django-bootstrap3==10.0.1
12   -django-debug-toolbar==1.9.1
13   -django-extensions==2.0.7
14   -django-suit==0.2.26
15   -django-test-without-migrations==0.6
16   -hyperlink==18.0.0
17   -idna==2.6
18   -incremental==17.5.0
19   -iso8601==0.1.12
20   -jdcal==1.4
21   -lxml==4.3.0
22   -mysqlclient==1.3.12
23   -numpy==1.16.0
24   -orderedmultidict==1.0
25   -pluggy==0.8.1
26   -py==1.5.3
27   -pytz==2018.4
28   -requests==2.18.4
29   -six==1.11.0
30   -sqlparse==0.2.4
31   -Twisted==18.4.0
32   -urllib3==1.22
33   -voevent-parse==1.0.3
34   -zope.interface==4.5.0
install/install_old.py deleted
... ... @@ -1,564 +0,0 @@
1   -import os, sys, subprocess, platform, fileinput, json, argparse, shutil
2   -
3   -DEBUG = False
4   -
5   -'''
6   - Pyros installation file (able to handle project configuration commands)
7   -'''
8   -
9   -
10   -class Utils:
11   - system = platform.system()
12   - columns = 100
13   - row = 1000
14   -
15   -
16   - def __init__(self):
17   - if (platform.system() != 'Windows'):
18   - try:
19   - rows, columns = os.popen('stty size', 'r').read().split()
20   - self.columns = int(columns)
21   - except:
22   - self.columns = 100
23   - if DEBUG:
24   - print("Could not get terminal size")
25   -
26   - def printFullTerm(self, color, string):
27   - value = int(self.columns / 2 - len(string) / 2)
28   - self.printColor(color, "-" * value, eol='')
29   - self.printColor(color, string, eol='')
30   - value += len(string)
31   - self.printColor(color, "-" * (self.columns - value))
32   - return 0
33   -
34   - def changeDirectory(self, path):
35   - if DEBUG:
36   - print("Moving to : " + path)
37   - os.chdir(path)
38   - if DEBUG:
39   - print("Current directory : " + str(os.getcwd()))
40   - return 0
41   -
42   - def replacePatternInFile(self, pattern, replace, file_path):
43   - try:
44   - with fileinput.FileInput(file_path, inplace=True, backup='.bak') as file:
45   - for line in file:
46   - print(line.replace(pattern, replace), end='')
47   - except:
48   - return 1
49   - return 0
50   -
51   - def printColor(self, color, message, file=sys.stdout, eol=os.linesep):
52   - if (self.system == 'Windows'):
53   - print(message, file=file, end=eol)
54   - else:
55   - print(color + message + Colors.ENDC, file=file, end=eol)
56   - return 0
57   -
58   -
59   -'''
60   - Python installer class
61   -'''
62   -
63   -
64   -class AInstaller(Utils):
65   - path = os.path.realpath(__file__)
66   - path_dir = os.getcwd()
67   - python_path = sys.executable
68   - python_version = sys.version_info
69   -
70   - commands = []
71   - commandMatcher = {}
72   - bin_dir = ""
73   - venv_pip = ""
74   - venv_bin = ""
75   - venv = ""
76   - venv_dir = ""
77   - requirements = ""
78   -
79   - current_command = "default"
80   - private = {}
81   - commands_list = []
82   - to_print = []
83   - executed = {}
84   - errors = {}
85   - defined_variables = {}
86   -
87   - def __init__(self, config):
88   - super(AInstaller, self).__init__()
89   - self.private = {
90   - "requirements": self.requirement,
91   - "create": self.create,
92   - }
93   - self.config = config
94   - self.commands = self.config.getCommandList()
95   - self.venv = self.config.getPath() + os.sep + self.config.getEnv()
96   - self.requirements = self.config.getReq()
97   - self.adaptInstaller()
98   - os.chdir(self.path_dir)
99   -
100   - def adaptInstaller(self):
101   - self.commandMatcher = self.config.getCommands()
102   - config = self.config.getConfig()
103   - if self.system == 'Windows':
104   - self.bin_dir = "Scripts"
105   - self.bin_name = "python.exe"
106   - self.pip_name = "pip.exe"
107   - else:
108   - self.bin_dir = "bin"
109   - self.bin_name = "python"
110   - self.pip_name = "pip"
111   - self.venv_pip = config["path"] + os.sep + config["env"] + os.sep + self.bin_dir + os.sep + self.pip_name
112   - self.venv_bin = config["path"] + os.sep + config["env"] + os.sep + self.bin_dir + os.sep + self.bin_name
113   - self.site_packages = config["path"] + os.sep + config["env"] + os.sep + "Lib" + os.sep + "site-packages" + os.sep
114   -
115   -
116   - '''
117   - Special functions
118   - '''
119   - def requirement(self):
120   - if (os.path.isfile(self.requirements)):
121   - if self.execProcessFromVenv(self.venv_pip + " install -r " + self.requirements):
122   - return 1
123   - else:
124   - self.printFullTerm(Colors.FAIL, "Requirements file " + self.requirements + " not found.")
125   - return 0
126   -
127   - def create(self):
128   - if (not os.path.isdir(self.venv)):
129   - #if self.execProcess("virtualenv " + self.venv + " -p " + self.python_path):
130   - if self.execProcess("python3 -m venv " + self.venv): #nouveau venv
131   - return 1
132   - else:
133   - self.printFullTerm(Colors.FAIL, "Virtual environment already exist")
134   - return 0
135   -
136   - '''
137   - Functions parameters
138   - '''
139   - def createConfig(self):
140   - configuration = self.config.createConfigFile()
141   - try:
142   - with open(self.config.getConfigFile(), "w") as f:
143   - f.write(json.dumps(configuration, sort_keys=True, indent=4))
144   - except Exception as e:
145   - print(e, file=sys.stderr)
146   - self.errors[self.current_command] = []
147   - return 1
148   - self.executed[self.current_command] = []
149   - return 0
150   -
151   - '''
152   - UTILS FUNCTIONS
153   - '''
154   - def setConfig(self, config):
155   - self.config = config
156   -
157   - def addExecuted(self, src, message):
158   - if (src in self.executed):
159   - self.executed[src].append(str(message))
160   - else:
161   - self.executed[src] = [str(message)]
162   - return 0
163   -
164   - def addError(self, src, message):
165   - if (src in self.errors):
166   - self.errors[src].append(str(message))
167   - else:
168   - self.errors[src] = [str(message)]
169   - return 0
170   -
171   - def execProcess(self, command):
172   - self.printFullTerm(Colors.BLUE, "Executing command [" + command + "]")
173   - process = subprocess.Popen(command, shell=True)
174   - process.wait()
175   - if process.returncode == 0:
176   - self.printFullTerm(Colors.GREEN, "Process executed successfully")
177   - self.addExecuted(self.current_command, command)
178   - else:
179   - self.printFullTerm(Colors.WARNING, "Process execution failed")
180   - self.addError(self.current_command, command)
181   - return process.returncode
182   -
183   - def execProcessFromVenv(self, command):
184   - args = command.split()
185   - self.create() #testing venv
186   - self.printFullTerm(Colors.BLUE, "Executing command from venv [" + str(' '.join(args[1:])) + "]")
187   - process = subprocess.Popen(args)
188   - process.wait()
189   - if process.returncode == 0:
190   - self.printFullTerm(Colors.GREEN, "Process executed successfully")
191   - self.addExecuted(self.current_command, str(' '.join(args[1:])))
192   - else:
193   - self.printFullTerm(Colors.WARNING, "Process execution failed")
194   - self.addError(self.current_command, str(' '.join(args[1:])))
195   - return process.returncode
196   -
197   - def askYesNoQuestion(self, message, question_tag, default=True):
198   - print(os.linesep * 2)
199   - self.printColor(Colors.BLUE, message + ": ", eol='')
200   - self.printColor(Colors.WARNING, "(default: " + ("Yes" if default else "No") + ") (Y/N)")
201   - self.printColor(Colors.BOLD, "Answer : ", eol='')
202   - sys.stdout.flush()
203   - answer = sys.stdin.readline().replace('\n', '').replace('\r', '')
204   - if answer == "Y" or answer == "y":
205   - self.defined_variables[question_tag] = True
206   - return True
207   - if (answer == ""):
208   - self.defined_variables[question_tag] = default
209   - return default
210   - self.defined_variables[question_tag] = False
211   - return False
212   -
213   - def askQuestion(self, message, default = ""):
214   - self.printColor(Colors.BLUE, message)
215   - self.printColor(Colors.BOLD, "Answer (default="+default+"): ", eol='')
216   - sys.stdout.flush()
217   - ret = sys.stdin.readline().replace('\n', '').replace('\r', '')
218   - if ret == "":
219   - return default
220   - return ret
221   -
222   - def addToPrint(self, message):
223   - self.to_print.append(message)
224   - return 0
225   -
226   -
227   -
228   - '''
229   - CORE
230   - '''
231   - def feed(self, array):
232   - self.commands_list = self.commands_list + array
233   - return 0
234   -
235   - def parse(self):
236   - try:
237   - for command in self.commands_list:
238   - if not isinstance(command, str):
239   - raise Exception("Invalid parameter + " + str(command))
240   - self.commands.append(command)
241   - except Exception as e:
242   - self.logError("An exception has been raised : " + str(e))
243   - return 1
244   - return 0
245   -
246   - def end(self):
247   - count = 0
248   -
249   - self.printFullTerm(Colors.WARNING, "Summary")
250   - self.printColor(Colors.GREEN, "Success : ")
251   - for command, valid in self.executed.items():
252   - if not valid:
253   - self.printColor(Colors.BLUE, "\t- Command : " + command + " successfully executed !")
254   - else:
255   - self.printColor(Colors.WARNING, "\t- In commmand : " + command)
256   - for exe in valid:
257   - self.printColor(Colors.GREEN, "\t\t - Command : " + exe + " successfully executed ! ")
258   - self.printColor(Colors.FAIL, "Errors : ")
259   - if not self.errors:
260   - self.printColor(Colors.GREEN, "\tNone")
261   - for command, items in self.errors.items():
262   - count += 1
263   - if (not items):
264   - self.printColor(Colors.FAIL, "Command : " + command + " failed !")
265   - else:
266   - self.printColor(Colors.WARNING, "\t- In commmand : " + command)
267   - for exe in items:
268   - self.printColor(Colors.FAIL, "\t\t - Command : " + exe + " failed.")
269   - if not self.errors:
270   - self.printFullTerm(Colors.BOLD, "Messages")
271   - for message in self.to_print:
272   - self.printColor(Colors.BOLD, message)
273   - return count
274   -
275   - def execCommand(self, command, matcher):
276   - if "normal" in matcher[command]:
277   - for c in matcher[command]["normal"]:
278   - if self.execProcess(c):
279   - return 1
280   - if "env_pip" in matcher[command]:
281   - for c in matcher[command]["env_pip"]:
282   - if c != "" and c:
283   - if self.execProcessFromVenv(self.venv_pip + " " + c):
284   - return 1
285   - if "env_bin" in matcher[command]:
286   - for c in matcher[command]["env_bin"]:
287   - if c != "" and c:
288   - if self.execProcessFromVenv(self.venv_bin + " " + c):
289   - return 1
290   - if "private" in matcher[command]:
291   - for c in matcher[command]["private"]:
292   - if c in self.private:
293   - if self.private[c]():
294   - return 1
295   - if "link" in matcher[command]:
296   - for link in matcher[command]["link"]:
297   - if (link in matcher and link != self.current_command):
298   - temp = self.current_command
299   - self.current_command = link
300   - if self.execCommand(link, matcher):
301   - return 1
302   - self.current_command = temp
303   - return 0
304   -
305   - def exec(self):
306   - if (not self.commands):
307   - return 0
308   - for command in self.commands:
309   - self.current_command = command
310   - if command == "init":
311   - self.createConfig()
312   - elif command in self.commandMatcher:
313   - if self.execCommand(command, self.commandMatcher):
314   - break
315   - else:
316   - self.logError("Invalid command : " + str(command))
317   - self.errors[command] = []
318   - return self.end()
319   -
320   - def logError(self, message):
321   - self.printColor(Colors.FAIL, "Installer : An error occurred [" + message + "]", file=sys.stderr)
322   - return 0
323   -
324   -'''
325   - Config Class
326   -'''
327   -
328   -
329   -class Config:
330   - __parser = argparse.ArgumentParser("Installer parser : launch it from the install directory.")
331   - __config_file = "install.json"
332   - __content = {
333   - "requirements": "REQUIREMENTS.txt",
334   - "path": "",
335   - "name": "default",
336   - "env": "venv"
337   - }
338   - __commands = {"install": {
339   - "env_bin": [],
340   - "env_pip": [],
341   - "normal": [
342   - ],
343   - "special": ["create"],
344   - "link": ["update"]
345   - }, "update": {
346   - "env_bin": [],
347   - "env_pip": [
348   - "install --upgrade pip",
349   - "install --upgrade wheel",
350   - ""
351   - ],
352   - "normal": [],
353   - "special": ["requirements"]
354   - }}
355   - usage = ""
356   - __command_list = []
357   -
358   - def __init__(self):
359   - self.__parser.add_argument("command", help="The command you want to execute")
360   - self.__parser.add_argument("--conf", help="Configuration file (.json)")
361   - self.__parser.add_argument("--path", help="Path where the virtual env will be created")
362   - self.__parser.add_argument("--name", help="Your configuration name")
363   - self.__parser.add_argument("--env", help="Your environment directory name")
364   - self.__parser.add_argument("--req", help="Your requirements file")
365   - self.usage = self.__parser.format_usage()
366   -
367   - def loadConfig(self):
368   - if not os.path.isfile(self.__config_file):
369   - return 0
370   - try:
371   - with open(self.__config_file) as data_file:
372   - data = json.load(data_file)
373   - for key, content in data.items():
374   - if key == "Configuration":
375   - for k, v in content.items():
376   - self.__content[k] = v
377   - else:
378   - self.__commands[key] = {}
379   - for k, v in content.items():
380   - self.__commands[key][k] = v
381   - if (DEBUG):
382   - print(json.dumps(self.__content, sort_keys=True, indent=4))
383   - print(json.dumps(self.__commands, sort_keys=True, indent=4))
384   - return 0
385   - except Exception as e:
386   - print(e, file=sys.stderr)
387   - return 1
388   -
389   - def createConfigFile(self):
390   - configuration = {}
391   - configuration["Configuration"] = self.__content
392   - configuration["install"] = self.__commands["install"]
393   - configuration["update"] = self.__commands["update"]
394   - return configuration
395   -
396   - def parse(self):
397   - try:
398   - res = self.__parser.parse_args(), self.__parser.format_usage()
399   - return (res)
400   - except SystemExit as e:
401   - # print(e, file=sys.stderr)
402   - sys.exit(1)
403   -
404   - def parseConf(self):
405   - res, usage = self.parse()
406   - try:
407   - if (res.conf):
408   - self.__config_file = res.conf
409   - if self.loadConfig():
410   - return 1
411   - if (res.path):
412   - self.__content["path"] = res.path
413   - if (res.req):
414   - self.__content["requirements"] = res.req
415   - if (res.name):
416   - self.__content["name"] = res.name
417   - if (res.env):
418   - self.__content["env"] = res.env
419   - self.__command_list.append(res.command)
420   - if self.__content["path"] == "":
421   - self.__content["path"] = "."
422   - return 0
423   - except Exception as e:
424   - print(e, file=sys.stderr)
425   - return 1
426   -
427   - def getReq(self):
428   - return self.__content["requirements"]
429   -
430   - def getPath(self):
431   - return self.__content["path"]
432   -
433   - def getEnv(self):
434   - return self.__content["env"]
435   -
436   - def getCommandList(self):
437   - return self.__command_list
438   -
439   - def getConfigFile(self):
440   - return self.__config_file
441   -
442   - def getCommands(self):
443   - return self.__commands
444   -
445   - def printUsage(self):
446   - print(self.usage, file=sys.stderr)
447   -
448   - def addConf(self, key, value):
449   - if isinstance(key, str) and isinstance(value, str):
450   - self.__content[key] = value
451   - return 0
452   - return 1
453   -
454   - def setConfigFile(self, conf_file):
455   - if os.path.isfile(conf_file):
456   - self.__config_file = conf_file
457   - return 0
458   - return 1
459   -
460   - def setPath(self, path):
461   - if (os.path.isdir(path)):
462   - if (path == ""):
463   - path = "."
464   - self.__content["path"] = path
465   - return 0
466   - return 1
467   -
468   - def setEnvName(self, name):
469   - self.__content["env"] = name
470   - return 0
471   -
472   - def setRequirements(self, req):
473   - if (os.path.isfile(req)):
474   - self.__content["requirements"] = req
475   - return 0
476   - return 1
477   -
478   - def setConfName(self, name):
479   - self.__content["name"] = name
480   - return 0
481   -
482   - def getConfig(self):
483   - return self.__content
484   -
485   -class Installer(AInstaller):
486   - sql = "CREATE DATABASE IF NOT EXISTS pyros; CREATE USER IF NOT EXISTS pyros; GRANT USAGE ON *.* TO 'pyros'; DROP USER 'pyros'; GRANT ALL ON pyros.* TO 'pyros'@'localhost' IDENTIFIED BY 'DjangoPyros'; GRANT ALL ON test_pyros.* TO 'pyros'@'localhost'"
487   - db_user = "pyros"
488   - db_password = "DjangoPyros"
489   -
490   - def __init__(self, config):
491   - super(Installer, self).__init__(config)
492   - # ADD YOUR PRIVATE FUNCTIONS HERE
493   - self.private["pyros"] = self.pyros
494   - if self.system == "Windows":
495   - self.requirements = "REQUIREMENTS_WINDOWS.txt"
496   - self.addToPrint("Please run 'python pyros.py server' then go to localhost:8000/admin and log in with these id")
497   - self.addToPrint("Username : " + self.db_user + " / Password : " + self.db_password)
498   -
499   - '''
500   - DEFINE YOUR PRIVATE FUNCTIONS HERE
501   - '''
502   - def pyros(self):
503   - if (self.current_command == "install"):
504   - if (self.system == 'Windows'):
505   - try:
506   - if (not os.path.isdir(self.site_packages + "voevent_parse-0.9.5.dist-info") and
507   - not os.path.isdir(self.site_packages + "voeventparse")):
508   - self.printFullTerm(Colors.BLUE, "Copying the voevent library in Lib/site-packages")
509   - shutil.copytree("windows" + os.sep + "voevent_parse-0.9.5.dist-info", self.site_packages + "voevent_parse-0.9.5.dist-info")
510   - shutil.copytree("windows" + os.sep + "voeventparse", self.site_packages + "voeventparse")
511   - except Exception as e:
512   - self.printFullTerm(Colors.FAIL, "Execution failed")
513   - self.addError(self.current_command, "Could not copy the voevent libs")
514   - return 1
515   - if self.execProcessFromVenv(self.venv_pip + " install windows\\lxml-3.6.0-cp35-cp35m-win32.whl"):
516   - return 1
517   - if ("database" not in self.defined_variables):
518   - self.askYesNoQuestion("Do you wish to use mysql in your project ? only if mysql is installed", question_tag="database", default=False)
519   - if (self.defined_variables["database"]):
520   - username = self.askQuestion("MYSQL Username", default="root")
521   - if (self.system == "Windows"):
522   - if (self.execProcess("echo " + self.sql + "|mysql -u "+ username + " -p") or
523   - self.replacePatternInFile("MYSQL = False", "MYSQL = True", "../src/pyros/settings.py")):
524   - return 1
525   - else:
526   - if (self.execProcess("echo \""+self.sql+"\" |mysql -u "+username+" -p") or
527   - self.replacePatternInFile("MYSQL = False", "MYSQL = True", "../src/pyros/settings.py")):
528   - return 1
529   - elif (self.current_command == "update"):
530   - if ("database" not in self.defined_variables):
531   - self.askYesNoQuestion("Do you wish to use mysql in your project ? only if mysql is installed",
532   - question_tag="database", default=False)
533   - if (self.defined_variables["database"]):
534   - if (self.system == 'Windows'):
535   - if self.execProcessFromVenv(self.venv_pip + " install windows\\mysqlclient-1.3.7-cp35-cp35m-win32.whl"):
536   - return 1
537   - else:
538   - if (self.execProcessFromVenv(self.venv_pip + " install mysqlclient==1.3.7")):
539   - return 1
540   - self.execProcessFromVenv(self.venv_bin + " ../pyros.py init_database")
541   - return 0
542   -
543   -
544   -'''
545   - Color class
546   -'''
547   -
548   -
549   -class Colors:
550   - HEADER = '\033[95m'
551   - BLUE = '\033[94m'
552   - GREEN = '\033[92m'
553   - WARNING = '\033[93m'
554   - FAIL = '\033[91m'
555   - ENDC = '\033[0m'
556   - BOLD = '\033[1m'
557   - UNDERLINE = '\033[4m'
558   -
559   -if __name__ == "__main__":
560   - conf = Config()
561   - if conf.parseConf():
562   - sys.exit(1)
563   - installer = Installer(conf)
564   - sys.exit(installer.exec())
install/requirements_django2.txt deleted
... ... @@ -1,67 +0,0 @@
1   -anyjson==0.3.3
2   -click
3   -DateTime==4.2
4   -Django==2.0.5
5   -django-admin-tools==0.8.1
6   -django-bootstrap3==10.0.1
7   -django-extensions==2.0.7
8   -
9   -# for Choices
10   -django-model-utils
11   -
12   -django-suit==0.2.26
13   -django-test-without-migrations==0.6
14   -#gunicorn==19.8.1
15   -iso8601==0.1.12
16   -jdcal==1.4
17   -#lxml==4.3.0
18   -lxml==4.5.1
19   -mysqlclient==1.3.12
20   -#pluggy>=0.7
21   -pluggy==0.8.1
22   -py==1.5.3
23   -pytz==2018.4
24   -requests==2.18.4
25   -six==1.11.0
26   -sqlparse==0.2.4
27   -Twisted==18.4.0
28   -voevent-parse==1.0.3
29   -zope.interface==5.2.0
30   -
31   -# For DEV
32   -django-debug-toolbar==1.9.1
33   -
34   -# Modifications 2021 :
35   -# removing plantuml because we need a unofficial version (maybe we could force to go back on an old version where the bug wasn't happening
36   -# added httplib2 which is needed for plantuml
37   -# added dataclasses which was missing for the model controller script
38   -#plantuml
39   -httplib2
40   -dataclasses
41   -# For YAML Config
42   -pykwalify
43   -PyYAML
44   -# For SP TAC Assignation
45   -matplotlib
46   -numpy
47   -# For Celery:
48   -##celery==3.1.23
49   -##flower==0.9.2
50   -##amqp==1.4.9
51   -##amqplib==1.0.2
52   -##billiard==3.3.0.23
53   -##kombu==3.0.37
54   -##django-celery==3.1.17
55   -
56   -# For working with GIT within Python
57   -GitPython
58   -
59   -# For working with date
60   -python-dateutil
61   -
62   -# Celme / guitastro packages
63   -pypylon
64   -sep
65   -astroquery
66   -astroalign
67   -ccdproc
68 0 \ No newline at end of file