With https://pypi.org/project/nestedtext/
import nestedtext as nt
def nestedText(self, reading=True, path="reviews.nt"):
if reading == True:
return nt.load(path)
elif reading != True:
nt.dump(reading, path)
return self.nestedText(path=path)
This code runs into errors following this journey:
return self.nestedText(path=path)
> return nt.load(self.fil[path])
> loader = NestedTextLoader(fp, top, source, on_dup, keymap, normalize_key)
> report('content must start with key or brace ({{).', lines.get_next())
> raise NestedTextError(template=message, *args, **kwargs)
> File "<string>", line 0 nestedtext.nestedtext.NestedTextError
The file starts off as only touched, so size 0. And then I run nestedText([]). Assume the path works, even if I put it incorrectly here. It is correct on my code that is not edited with names as such.
What am I doing wrong?
Related
I have a function that does some file operations and
makes an entry for that IP to /etc/hosts file for DNS resolution
def add_hosts_entry():
ip_addr = "1.2.3.4"
HOST_FILE_PATH = "/etc/hosts"
reg_svc_name = "SVC_NAME"
try:
with open(HOST_FILE_PATH, 'r+') as fp:
lines = fp.readlines()
fp.seek(0)
fp.truncate()
for line in lines:
if not reg_svc_name in line:
fp.write(line)
fp.write(f"{ip_addr}\t{reg_svc_name}\n")
except FileNotFoundError as ex:
LOGGER.error(f"Failed to read file. Details: {repr(ex)}")
sys.exit(1)
LOGGER.info(
f"Successfully made entry in /etc/hosts file:\n{ip_addr}\t{reg_svc_name}"
)
I want to test that there is indeed an IP entry in the file that I
made.
and that there is only 1 IP address that maps to reg_svc_name
I found how to mock open().
I have this so far but not sure how to check for above two cases:
#pytest.fixture
def mocker_etc_hosts(mocker):
mocked_etc_hosts_data = mocker.mock_open(read_data=etc_hosts_sample_data)
mocker.patch("builtins.open", mocked_etc_hosts_data)
def test_add_hosts_entry(mocker_etc_hosts):
with caplog.at_level(logging.INFO):
registry.add_hosts_entry()
# how to assert??
Solution 1
Don't mock the open functionality because we want it to actually update a file that we can check. Instead, intercept it and open a test file instead of the actual file used in the source code. Here, we will use tmp_path to create a temporary file to be updated for the test.
src.py
def add_hosts_entry():
ip_addr = "1.2.3.4"
HOST_FILE_PATH = "/etc/hosts"
reg_svc_name = "SVC_NAME"
try:
with open(HOST_FILE_PATH, 'r+') as fp:
lines = fp.readlines()
fp.seek(0)
fp.truncate()
for line in lines:
if not reg_svc_name in line:
fp.write(line)
fp.write(f"{ip_addr}\t{reg_svc_name}\n")
except FileNotFoundError as ex:
print(f"Failed to read file. Details: {repr(ex)}")
else:
print(f"Successfully made entry in /etc/hosts file:\n{ip_addr}\t{reg_svc_name}")
test_src.py
import pytest
from src import add_hosts_entry
#pytest.fixture
def etc_hosts_content_raw():
return "some text\nhere\nSVC_NAME\nand the last!\n"
#pytest.fixture
def etc_hosts_content_updated():
return "some text\nhere\nand the last!\n1.2.3.4\tSVC_NAME\n"
#pytest.fixture
def etc_hosts_file(tmp_path, etc_hosts_content_raw):
file = tmp_path / "dummy_etc_hosts"
file.write_text(etc_hosts_content_raw)
return file
#pytest.fixture
def mocker_etc_hosts(mocker, etc_hosts_file):
real_open = open
def _mock_open(file, *args, **kwargs):
print(f"Intercepted. Would open {etc_hosts_file} instead of {file}")
return real_open(etc_hosts_file, *args, **kwargs)
mocker.patch("builtins.open", side_effect=_mock_open)
def test_add_hosts_entry(
mocker_etc_hosts, etc_hosts_file, etc_hosts_content_raw, etc_hosts_content_updated
):
assert etc_hosts_file.read_text() == etc_hosts_content_raw
add_hosts_entry()
assert etc_hosts_file.read_text() == etc_hosts_content_updated
Output
$ pytest -q -rP
. [100%]
============================================== PASSES ===============================================
_______________________________________ test_add_hosts_entry ________________________________________
--------------------------------------- Captured stdout call ----------------------------------------
Intercepted. Would open /tmp/pytest-of-nponcian/pytest-13/test_add_hosts_entry0/dummy_etc_hosts instead of /etc/hosts
Successfully made entry in /etc/hosts file:
1.2.3.4 SVC_NAME
1 passed in 0.05s
If you're interested, you can display the temporary dummy file too to see the result of the process:
$ cat /tmp/pytest-of-nponcian/pytest-13/test_add_hosts_entry0/dummy_etc_hosts
some text
here
and the last!
1.2.3.4 SVC_NAME
Solution 2
Mock open as well as the .write operation. Once mocked, see all the calls to the mocked .write via call_args_list. This isn't recommended as it would feel like we are writing a change-detector test which is tightly coupled to how the source code was implemented line by line rather than checking the behavior.
Say I have a class:
class Example:
__slots__ = ("_attrs", "other_value")
def __init__(self):
self._attrs = OrderedDict()
self.other_value = 1
self.attribute = 0
def __setattr__(self, key, value):
if key in self.__slots__:
return super().__setattr__(key, value)
else:
self._attrs[key] = value
def __getattr__(self, key):
return self._attrs[key]
The goal is to have Example have two slots:
if those are set, then set them as usual. (works)
If additional attributes are set, assign them in _attrs. (works)
For getting attributes, the code should:
Act as usual if anything from slots is requested (works)
get the value from _attrs if it exists in _attrs.keys() (works)
error in any other case as usual (issue).
For the issue, I'd like the error to mimic what would normally happen if an attribute was not present for an object. Currently when running code I get a key error on self._attrs. Although this is fine, it would be nice for it to hide this nuance away. More annoyingly, if I debug in Pycharm, the autocomplete will chuck out a large error trying to look at dict before I've even hit enter:
Example().abc # hit tab in pycharm
# returns the error:
Traceback (most recent call last):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 1464, in do_it
def do_it(self, dbg):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 159, in generate_completions_as_xml
def generate_completions_as_xml(frame, act_tok):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 77, in complete
def complete(self, text):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 119, in attr_matches
def attr_matches(self, text):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py", line 165, in generate_imports_tip_for_module
def generate_imports_tip_for_module(obj_to_complete, dir_comps=None, getattr=getattr, filter=lambda name:True):
File "/Users/xxxxxxxxx/", line 46, in __getattr__
def __getattr__(self, key: str) -> None:
KeyError: '__dict__'
Is there a way to suppress this by writing the code differently?
You might be able to make it work by implementing __dir__ on the class, so it has a canonical source of names that can be completed:
def __dir__(self):
return 'other_value', *self._attrs.keys()
I can't swear to how PyCharm implements their tab-completion, so there's no guarantee it works, but this is the way to define the set of enumerable attributes for a type, and hopefully PyCharm will use it when available, rather than going for __dict__.
The other approach (and this is probably a good idea regardless) it to make sure you raise the right error when __getattr__ fails so PyCharm knows the problem is a missing attribute, not some unrelated issue with a dict:
def __getattr__(self, key):
try:
return self._attrs[key]
except KeyError:
raise AttributeError(key)
I am making an app which will return one random line from the .txt file. I made a class to implement this behaviour. The idea was to use one method to open file (which will remain open) and the other method which will close it after the app exits. I do not have much experience in working with files hence the following behaviour is strange to me:
In __init__ I called self.open_file() in order to just open it. And it works fine to get self.len. Now I thought that I do not need to call self.open_file() again, but when I call file.get_term()(returns random line) it raises IndexError (like the file is empty), But, if I call file.open_file() method again, everything works as expected.
In addition to this close_file() method raises AttributeError - object has no attribute 'close', so I assumed the file closes automatically somehow, even if I did not use with open.
import random
import os
class Pictionary_file:
def __init__(self, file):
self.file = file
self.open_file()
self.len = self.get_number_of_lines()
def open_file(self):
self.opened = open(self.file, "r", encoding="utf8")
def get_number_of_lines(self):
i = -1
for i, line in enumerate(self.opened):
pass
return i + 1
def get_term_index(self):
term_line = random.randint(0, self.len-1)
return term_line
def get_term(self):
term_line = self.get_term_index()
term = self.opened.read().splitlines()[term_line]
def close_file(self):
self.opened.close()
if __name__ == "__main__":
print(os.getcwd())
file = Pictionary_file("pictionary.txt")
file.open_file() #WITHOUT THIS -> IndexError
file.get_term()
file.close() #AttributeError
Where is my mistake and how can I correct it?
Here in __init__:
self.open_file()
self.len = self.get_number_of_lines()
self.get_number_of_lines() actually consumes the whole file because it iterates over it:
def get_number_of_lines(self):
i = -1
for i, line in enumerate(self.opened):
# real all lines of the file
pass
# at this point, `self.opened` is empty
return i + 1
So when get_term calls self.opened.read(), it gets an empty string, so self.opened.read().splitlines() is an empty list.
file.close() is an AttributeError, because the Pictionary_file class doesn't have the close method. It does have close_file, though.
I was working on some code which retrieves a line in a text file ("save[#]) with the format:
"[name],[boolean or integer value]"
(The aim is to be able to retrieve it for save states of a game)
The issue is that whenever I try to return a value from my module I get the following:
Traceback (most recent call last):
File "//IHS-FS-001.ihs.local/Cohort2020$/2ELGAG1/python/srctg/test.py", line 5, in <module>
retrieve()
File "//IHS-FS-001.ihs.local/Cohort2020$/2ELGAG1/python/srctg/test.py", line 3, in retrieve
if retrieve.check("test", 1) == True:
AttributeError: 'function' object has no attribute 'check'
The test attribute is a testing module set up to test the code for the game:
import retrieve.py
def retrieve():
if retrieve.check("test", 1) == True:
return True
retrieve()
The retrieve attribute itself is set up like so:
import error
def check(i_name, save):
save = str(save)
save_n = "save" + save + ".txt"
save_f = open(save_n, "r")
list = save_f.readlines()
for item in range(len(list)):
list[item] = list[item].strip()
list[item] = list[item].split(",")
list[item][1] = list[item][1]
for item in range(len(list)):
if i_name == list[item][0]:
i_return = list[item][1]
if bool_check(i_return) == True:
i_return = bool(i_return)
elif int_check(i_return) == True:
i_return = int(i_return)
else:
print(error.code("001"))
return "error"
return i_return
def int_check(value):
while True:
try:
value = int(value)
return True
break
except ValueError:
return False
break
def bool_check(value):
while True:
try:
value = bool(value)
return True
break
except ValueError:
return False
break
Don't include the .py in the import. This tries to import a module named py inside the package named retrieve, which is probably not what you meant.
import retrieve as retrieve_module
def retrieve():
if retrieve_module.check("test", 1) == True:
return True
Also, don't write a function with the same name as the module you just imported. Change the name of one or the other. That's why it can't find the .check attribute. It's looking inside the retrieve function instead of inside the retrieve module because you overwrote it in the global namespace (by executing the function definition) before you called the function.
Hy,
Yeah so, i am writing an python3 programm, that should send the content of an file to an LPC1758.
For testing i will write a simple string above USB. I use libusb1.0 ....
But every time i become the same error, even if i rename "dev" into "device" the error is the same.
--> AttributeError: 'MainWindow' object has no attribute 'dev'<--
class MainWindow(QtGui.QMainWindow, form_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.pb_send.clicked.connect(self.pb_send_clicked)
self.pb_open.clicked.connect(self.pb_open_clicked)
self.pb_exit.clicked.connect(self.pb_exit_clicked)
# SEND button event handler
def pb_send_clicked(self):
send = "Yo Man"
bulk_out_ep = 0x05
bulk_in_ep = 0x82
interface = 0
length = 30
dev = usb.core.find(idVendor= 0xfefe, idProduct= 0x0001)
cfg = usb.control.get_configuration(dev) # get current configuration
print(dev)
if dev is None:
self.USB_label.setText("Device not found !!!")
raise ValueError('Device not found')
else:
self.USB_label.setText("Device found")
found = 1
if(cfg != 1): # check if device is configured
usb.DeviceHandle.setConfiguration(self, 1)
usb.util.claim_interface(dev, interface)
usb.DeviceHandle.bulkWrite(self,bulk_out_ep,send)
print("wrote to estick")
readData = usb.DeviceHandle.bulkRead(self, bulk_in_ep, length)
print("read from estick: "+ readData)
usb.util.release_interface(dev, interface)
This is what Stacktrace shows:
Traceback (most recent call last):
File "/home/user/workspace_Qt/ESS_project/ess_project.py", line 93, in pb_send_clicked
readData = usb.DeviceHandle.bulkRead(self,endpoint=bulk_in_ep,size=length)
File "/usr/lib/python3.3/usb/legacy.py", line 159, in bulkRead
return self.dev.read(endpoint, size, self.__claimed_interface, timeout)
AttributeError: 'MainWindow' object has no attribute 'dev'
dev is a member of the class DeviceHandle which is the type of the first parameter expected by the setConfiguration functions.
And setConfiguration expects 2 parameters instead of 1, because you are calling the method on the class usb.DeviceHandle instead of calling it on an object of type usb.DeviceHandle, you should use:
dev.setConfiguration(1)
(same thing for bulkWrite and bulkRead).
Also the get_configuration method returns a Configuration object instead of a number, so cfg != 1 will always be true (this may work with cfg.index != 1 instead but I'm not sure).