Skip to content

Commit 5cdfa26

Browse files
committed
initial commit
1 parent 85d2ade commit 5cdfa26

File tree

6 files changed

+165
-9
lines changed

6 files changed

+165
-9
lines changed

conftest.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import re
2+
import ast
3+
4+
import parso
5+
import pytest
6+
7+
from pathlib import Path
8+
from redbaron import RedBaron
9+
from redbaron.utils import indent
10+
11+
12+
class SourceCode:
13+
def __init__(self, exists, code):
14+
self.exists = exists
15+
self.code = code
16+
17+
18+
class Parser:
19+
def __init__(self, filename):
20+
self.code = ""
21+
self.message = ""
22+
23+
error_message = ""
24+
error_start_pos = ""
25+
26+
if filename == "sensor":
27+
file_path = Path.cwd() / "sensor.py"
28+
else:
29+
file_path = Path.cwd() / "sensor" / "{}.py".format(filename)
30+
31+
grammar = parso.load_grammar()
32+
module = grammar.parse(path=file_path.resolve())
33+
self.success = len(grammar.iter_errors(module)) == 0
34+
35+
if self.success:
36+
with open(file_path.resolve(), "r") as source_code:
37+
self.code = RedBaron(source_code.read())
38+
else:
39+
error_message = grammar.iter_errors(module)[0].message
40+
error_start_pos = grammar.iter_errors(module)[0].start_pos[0]
41+
self.message = "{} on or around line {} in `{}`.".format(
42+
error_message, error_start_pos, file_path.name
43+
)
44+
45+
def get_by_name(self, type, name, code=None):
46+
if code is None:
47+
item = self.code.find_all(type, lambda node: node.name == name)
48+
else:
49+
item = code.find_all(type, lambda node: node.name == name)
50+
51+
return SourceCode(True, item[0]) if len(item) > 0 else SourceCode(False, [])
52+
53+
def get_call(self, value, code):
54+
call = code.find("call", lambda node: node.previous.value == value)
55+
return SourceCode(True, call) if call is not None and len(call) > 0 else SourceCode(False, [])
56+
57+
def get_args(self, code):
58+
return list(
59+
code.find_all("call_argument").map(
60+
lambda node: str(node.target) + ":" + str(node.value).replace("'", '"')
61+
)
62+
)
63+
64+
def get_by_value(self, type, value, code=None):
65+
if code is None:
66+
item = self.code.find_all(type, lambda node: str(node.target) == value)
67+
else:
68+
item = code.find_all(type, lambda node: str(node.target) == value)
69+
return SourceCode(True, item[0]) if len(item) > 0 else SourceCode(False, [])
70+
71+
def get_imports(self):
72+
imports = []
73+
self.code.find_all(
74+
"import",
75+
lambda node: node.find_all(
76+
"dotted_as_name", lambda node: imports.append(str(node))
77+
),
78+
)
79+
return imports
80+
81+
def get_from_import(self, value):
82+
imports = self.code.find_all(
83+
"from_import",
84+
lambda node: "".join(list(node.value.node_list.map(lambda node: str(node))))
85+
== value,
86+
).find_all("name_as_name")
87+
return list(imports.map(lambda node: node.value))
88+
89+
def flatten(self, dictionary):
90+
def _flatten(node):
91+
trimmed = re.sub(r"\"|'", "", node.key.value)
92+
flattened = []
93+
if node.value.type is "list":
94+
for item in node.value.node_list:
95+
if item.type is not "comma":
96+
flattened.append("{}:{}".format(trimmed, str(item)))
97+
else:
98+
flattened.append("{}:{}".format(trimmed, node.value.value))
99+
100+
return flattened
101+
102+
items = list(dictionary.find_all("dictitem").map(lambda node: _flatten(node)))
103+
return [item for sublist in items for item in sublist]
104+
105+
def get_conditional(self, values, type, nested=False):
106+
def flat(node):
107+
if node.type == "comparison":
108+
return "{}:{}:{}".format(
109+
str(node.first).replace("'", '"'),
110+
str(node.value).replace(" ", ":"),
111+
str(node.second).replace("'", '"'),
112+
)
113+
elif node.type == "unitary_operator":
114+
return "{}:{}".format(
115+
str(node.value), str(node.target).replace("'", '"')
116+
)
117+
118+
nodes = self.code.value if nested else self.code
119+
for value in values:
120+
final_node = nodes.find_all(type).find(
121+
["comparison", "unitary_operator"], lambda node: flat(node) == value
122+
)
123+
if final_node is not None:
124+
return final_node
125+
return None
126+
127+
128+
@pytest.fixture
129+
def parse():
130+
def _parse(filename):
131+
return Parser(filename)
132+
133+
return _parse

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[pytest]
2-
addopts = --tb=short -p no:warnings
2+
addopts = -rN --tb=short -p no:warnings

requirements.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ pytest==5.3.5
55
pytest-json-report==1.2.1
66
pytest-metadata==1.8.0
77
pytest-sugar==0.9.2
8-
python-dateutil==2.7.5
9-
py==1.7.0
10-
pyparsing==2.3.0
11-
more-itertools==4.3.0
8+
PyYAML==5.3
9+
redbaron==0.9.2
10+
typer==0.0.8

sensor.py

Whitespace-only changes.

tasks.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
- [Module 01 - The Sensor Class](#module-01---the-sensor-class)
44
- [Status](#status)
55
- [Module 1: System Setup](#module-1-system-setup)
6-
- [Module 2: Load Data From Files](#module-2-load-data-from-files)
6+
- [Task 1: Import os, glob, and csv](#task-1-import-os-glob-and-csv)
77
- [Module 3: Create a Class HomeData](#module-3-create-a-class-homedata)
88
- [Module 4: Analyze Temperature Data](#module-4-analyze-temperature-data)
99
- [Module 5: Analyze Humidity Data](#module-5-analyze-humidity-data)
@@ -14,14 +14,24 @@
1414

1515
Draft.
1616

17-
## Module 1: System Setup
17+
## Module 1: Load Sensor Data From Files
1818

19-
## Module 2: Load Data From Files
19+
### Task 1: Import os, glob, and csv
20+
21+
//]: # (@pytest.mark.test_site_path_import_module1)
2022

2123
```python
22-
from sensor_file import Sensor
24+
import os
25+
import glob
26+
import csv
2327
```
2428

29+
In this module we'll build up a function to parse to data files with the sensor information.
30+
31+
Class that will set configuration values and create the root structure of our static site. We'll also create a command line tool using the `Typer` library. Since we are going to be working with paths let's import `pathlib`, which is part of the standard library.
32+
33+
Open the `site.py` located in the `ssg` directory. At the top import `Path` from `pathlib`.
34+
2535
## Module 3: Create a Class HomeData
2636

2737
## Module 4: Analyze Temperature Data

tests/test_module1.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
1+
12
import re
23
import pytest
4+
5+
6+
@pytest.mark.test_site_sys_import_module1
7+
def test_site_sys_import_module1(parse):
8+
# import sys
9+
10+
# test file exist
11+
sensor = parse("load_info")
12+
assert sensor.success, sensor.message
13+
14+
# test import sys
15+
sys_import = "sys" in sensor.get_imports()
16+
assert sys_import, "Have you imported `sys`?"

0 commit comments

Comments
 (0)