Skip to content

Commit ae07c7a

Browse files
tg359Fraser Greenroyd
authored andcommitted
updated analytics
1 parent 631ddf8 commit ae07c7a

14 files changed

Lines changed: 176 additions & 60 deletions

Python_Engine/Compute/InstallBasePythonEnvironment.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ public static oM.Python.PythonEnvironment InstallBasePythonEnvironment(bool run
108108
}
109109

110110
// install packages into base environment
111-
string packageInstallationCommand = $"{executable} -m pip install --no-warn-script-location -e {Path.Combine(Query.CodeDirectory(), Query.ToolkitName())}";
111+
string baseBHoMPackage = Path.Combine(Query.CodeDirectory(), Query.ToolkitName());
112+
string packageInstallationCommand = $"{executable} -m pip install --no-warn-script-location -e {baseBHoMPackage}";
112113
sw.WriteLine($"[{System.DateTime.Now.ToString("s")}] {packageInstallationCommand}");
113114
sw.WriteLine(Compute.RunCommandStdout($"{packageInstallationCommand}", hideWindows: true)); // install packages into this environment
114115
}

Python_Engine/Compute/InstallReferencedVirtualenv.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ public static oM.Python.PythonEnvironment InstallReferencedVirtualenv(
8686
string logFile = Path.Combine(targetDirectory, "installation.log");
8787

8888
// create installation commands
89+
string baseBHoMPackage = Path.Combine(Query.CodeDirectory(), baseEnv.Name);
8990
List<string> installationCommands = new List<string>() {
9091
$"{bhomPythonExecutable} -m virtualenv --python={executable} {targetDirectory}", // create the virtualenv of the target executable
9192
$"{executable} -m pip freeze > {Path.Combine(targetDirectory, "requirements.txt")}", // get the installed packages from the referenced executable
9293
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install -r {Path.Combine(targetDirectory, "requirements.txt")}", // install requirements into virtualenv
93-
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install ipykernel", // install ipykernel into virtualenv
94-
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install pytest", // install pytest into virtualenv
94+
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install ipykernel pytest", // install ipykernel and pytest into virtualenv
9595
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m ipykernel install --name={name}", // register environment with ipykernel
96+
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install --no-warn-script-location -e {baseBHoMPackage}", // install base BHoM package to virtualenv
9697
};
9798
if (localPackage != null)
9899
installationCommands.Add($"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install -e {Modify.AddQuotesIfRequired(localPackage)}"); // install local package into virtualenv

Python_Engine/Compute/InstallVirtualenv.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,16 @@ public static oM.Python.PythonEnvironment InstallVirtualenv(
8181
string logFile = Path.Combine(targetDirectory, "installation.log");
8282

8383
// create installation commands
84+
string baseBHoMPackage = Path.Combine(Query.CodeDirectory(), baseEnv.Name);
8485
List<string> installationCommands = new List<string>() {
8586
$"{bhomPythonExecutable} -m virtualenv --python={executable} {targetDirectory}", // create the virtualenv of the target executable
86-
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install ipykernel", // install ipykernel into virtualenv
87-
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install pytest", // install pytest into virtualenv
87+
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install ipykernel pytest", // install ipykernel and pytest into virtualenv
8888
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m ipykernel install --name={name}", // register environment with ipykernel
89-
};
89+
$"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install --no-warn-script-location -e {baseBHoMPackage}", // install base BHoM package to virtualenv
90+
};
9091
if (localPackage != null)
9192
installationCommands.Add($"{Path.Combine(targetDirectory, "Scripts", "activate")} && python -m pip install -e {Modify.AddQuotesIfRequired(localPackage)}"); // install local package into virtualenv
92-
93+
9394

9495
using (StreamWriter sw = File.AppendText(logFile))
9596
{
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import functools
2+
import inspect
3+
import sys
4+
import traceback
5+
from json import dump
6+
from pathlib import Path
7+
from typing import Callable
8+
from uuid import uuid4
9+
10+
from python_toolkit.bhom.encoder import Encoder
11+
from python_toolkit.bhom.ticks import ticks
12+
from python_toolkit.bhom.version import version
13+
14+
ASSEMBLIES_DIR = Path(r"C:\ProgramData\BHoM\Assemblies")
15+
LOGGING_DIR = Path(r"C:\ProgramData\BHoM\Logs")
16+
LOGGING_DIR.mkdir(exist_ok=True, parents=True)
17+
18+
19+
def analytics(f: Callable):
20+
"""A wrapper used to capture usage analytics of the decorated function."""
21+
22+
@functools.wraps(f)
23+
def wrapper(*args, **kwargs):
24+
25+
bhom_version = ".".join([str(i) for i in version((ASSEMBLIES_DIR / "BHoM.dll").as_posix())][:2])
26+
ui_name = "PythonBHoM"
27+
ticks_value = ticks()
28+
29+
_, module_stack, _, file_path = str(inspect.getmodule(f)).split(" ")
30+
module_stack = module_stack[1:-1]
31+
32+
log_file = LOGGING_DIR / f"Usage_{ui_name}_{ticks_value}.log"
33+
34+
# gather metadata around current callable instance
35+
d = {
36+
"BHoMVersion": bhom_version,
37+
"BHoM_Guid": str(uuid4()),
38+
"CallerName": f"{module_stack}",
39+
"ComponentId": "",
40+
"CustomData": {},
41+
"Errors": [],
42+
"FileId": "",
43+
"FileName": "",
44+
"Fragments": [],
45+
"Name": "",
46+
"ProjectID": "",
47+
"SelectedItem":
48+
{
49+
"Name": f.__name__,
50+
"_bhomVersion": bhom_version,
51+
"_t": "Python"
52+
},
53+
"Tags": [],
54+
"Time":
55+
{
56+
"$date": ticks_value
57+
},
58+
"UI": ui_name,
59+
"UiVersion": sys.version,
60+
"_bhomVersion": bhom_version,
61+
"_t": "BH.oM.UI.UsageLogEntry"
62+
}
63+
64+
# run method and capture errors
65+
try:
66+
f(*args, **kwargs)
67+
except Exception:
68+
d["Errors"].append(traceback.format_exc())
69+
70+
with open(log_file, "w+") as fp:
71+
dump(d, fp, cls=Encoder)
72+
73+
# print function here to enable downstream processes to access the location where the data is stored for loading into BHoM.
74+
print(log_file, file=sys.stdout)
75+
76+
return f(*args, **kwargs)
77+
78+
return wrapper
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from pathlib import Path
2+
3+
def anonymise_filepath(filepath):
4+
"""Remove user identifying information from a filepath
5+
NOTE: This currently only removes <USERNAME> from after "Users".
6+
"""
7+
8+
fp = Path(filepath)
9+
file_parts = list(fp.parts)
10+
11+
username_index = None
12+
for n, part in enumerate(file_parts):
13+
if part.lower() == "users":
14+
username_index = n + 1
15+
16+
if username_index is None:
17+
return fp.as_posix()
18+
19+
file_parts[username_index] = "<USERNAME>"
20+
21+
return Path(*file_parts).as_posix()

Python_Engine/Python/src/python_toolkit/bhom/bhom_analytics.py

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import types
2+
3+
4+
def decorate_all_in_module(module, decorator):
5+
for name in dir(module):
6+
obj = getattr(module, name)
7+
if isinstance(obj, types.FunctionType):
8+
setattr(module, name, decorator(obj))

Python_Engine/Python/src/python_toolkit/bhom/bhom_json_encoder.py renamed to Python_Engine/Python/src/python_toolkit/bhom/encoder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pandas as pd
77

88

9-
class BHoMJSONEncoder(JSONEncoder):
9+
class Encoder(JSONEncoder):
1010
"""A custom BHoM JSONEncoder class capable of serialising non-native Python datatypes into a JSONable object."""
1111

1212
def default(self, obj):
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import importlib.util
2+
from pathlib import Path
3+
import os
4+
5+
MODULE_EXTENSIONS = '.py'
6+
7+
def package_contents(package_name, exclude = None):
8+
"""Recursively traverse a module to find all packages within, and return these as a list of strings"""
9+
10+
spec = importlib.util.find_spec(package_name)
11+
if spec is None:
12+
return set()
13+
14+
pathname = Path(spec.origin).parent
15+
ret = set()
16+
with os.scandir(pathname) as entries:
17+
for entry in entries:
18+
if entry.name.startswith('__'):
19+
continue
20+
current = '.'.join((package_name, entry.name.partition('.')[0]))
21+
if entry.is_file():
22+
if exclude is not None:
23+
for x in exclude:
24+
if x in entry.name:
25+
continue
26+
if entry.name.endswith(MODULE_EXTENSIONS):
27+
ret.add(current)
28+
elif entry.is_dir():
29+
ret.add(current)
30+
ret |= package_contents(current)
31+
32+
return ret
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from datetime import datetime
2+
3+
def ticks():
4+
"""Return the number of ticks since 0001:01:01 00:00:00"""
5+
return int((datetime.utcnow() - datetime(1, 1, 1)).total_seconds())

0 commit comments

Comments
 (0)