I'm trying to manage a directory tree which is created through a hierarchy of Python objects. I want to serialize the top-level object in JSON so I can share 2 things with users: the JSON file along with the directory. I'd like other users to be able to point to that directory, so the problem here is setting that root directory which might change on a different computer.
Here's an example of what I have right now:
import os.path as op
class Top():
def __init__(self, root_dir):
self._root_dir = root_dir
intop = InTop(self.base_dir)
self.intop = intop
#property
def root_dir(self):
return self._root_dir
#root_dir.setter
def root_dir(self, path):
self._root_dir = path
#property
def base_dir(self):
return op.join(self.root_dir, 'Top')
class InTop():
def __init__(self, root_dir):
self._intop_dir = op.join(root_dir, 'InTop')
#property
def intop_dir(self):
return self._intop_dir
#intop_dir.setter
def intop_dir(self, path):
self._intop_dir = path
I'm happy with how this works right now for updating the path in a Top object:
t = Top('~/projects/')
print(t.root_dir) # ~/projects/
print(t.base_dir) # ~/projects/Top
t.root_dir = '~/Downloads/'
print(t.root_dir) # ~/Downloads/
print(t.base_dir) # ~/Downloads/Top
But is there any way for that change to propagate to the InTop object?
t = Top('~/projects/')
print(t.root_dir) # ~/projects/
print(t.base_dir) # ~/projects/Top
print(t.intop.intop_dir) # ~/projects/Top/InTop
t.root_dir = '~/Downloads/'
print(t.root_dir) # ~/Downloads/
print(t.base_dir) # ~/Downloads/Top
print(t.intop.intop_dir) # ~/projects/Top/InTop <--- How to update this?
How do I get that last line to print "~/Downloads/Top/InTop" instead?
Perhaps there is a better way to manage relative file paths like this - if so please let me know.
Thanks in advance!
Figured it out..just needed to set it within the Top setter (also corrected my setters)
import os.path as op
class Top(object):
def __init__(self, root_dir):
self._root_dir = root_dir
intop_obj = InTop(self.top_dir)
self.intop = intop_obj
#property
def root_dir(self):
return self._root_dir
#root_dir.setter
def root_dir(self, path):
self._root_dir = path
self.intop.top_dir = self.top_dir
#property
def top_dir(self):
return op.join(self.root_dir, 'Top')
class InTop(object):
def __init__(self, top_dir):
self._top_dir = top_dir
#property
def top_dir(self):
return self._top_dir
#top_dir.setter
def top_dir(self, top_dir):
self._top_dir = top_dir
#property
def intop_dir(self):
return op.join(self.top_dir, 'InTop')
Gets me:
t = Top('~/projects/')
print(t.root_dir) # ~/projects/
print(t.top_dir) # ~/projects/Top
print(t.intop.intop_dir) # ~/projects/Top/InTop
t.root_dir = '~/Downloads/'
print(t.root_dir) # ~/Downloads/
print(t.top_dir) # ~/Downloads/Top
print(t.intop.intop_dir) # ~/Downloads/Top/InTop
Related
I need to have 100 of those similar python scripts that have MyData class from MyData_1 to MyData_100.
import torch
import numpy as np
from torch_geometric.data import InMemoryDataset, Data
from torch_geometric.utils import to_undirected
class MyData_1(InMemoryDataset):
def __init__(self, root, transform=None):
super(MyData_1, self).__init__(root, transform)
self.data, self.slices = torch.load(self.processed_paths[0])
#property
def raw_file_names(self):
return "mydata_1.npz"
#property
def processed_file_names(self):
return "data_1.pt"
def process(self):
raw_data = np.load(self.raw_paths[0])
cluster_data = torch.load('./raw/total_clusters.pt')
x = torch.from_numpy(raw_data['x'])
y = torch.from_numpy(raw_data['y'])
pos = torch.stack([x,y], dim=-1)
cp = torch.from_numpy(raw_data['cp'])
data_list = []
for i in range(cp.size(0)):
data = Data(x=cp[i].view(-1,1),pos=pos.view(-1,2), cluster=cluster_data[0])
data_list.append(data)
torch.save(self.collate(data_list), self.processed_paths[0])
I'm trying to do this because each MyData class calls different mydata_1,2,...100.npz to generate dataset.
Is there any way to make this fast?
Thanks in advance!
I didn't fully understand the reason why you need to create 100 different classes.
Is it because you need to return mydata_1.npz to mydata_100.npz? If then, You can create a single class like this:
class Myclass:
def __init__(self, index):
self.index = index
def raw_file_names(self):
return "mydata_{}.npz".format(self.index)
Then, at another script like main.py, you can create/assign it like:
for i in range(100):
exec('dataset_{} = MyData_{}({})'.format(i, i, i))
I believe you can build your own code that fits your problem with above examples.
You can achieve this by creating Metaclass(subclass ) below is a example how to pass dynamic name of class in subclass magicfunction
MyDynamicSubclass
class MyClass:
def __init_subclass__(cls, my_name):
print(f"Subclass created and my name is {my_name}")
print(cls, cls.__class__.__name__)
MyDynamicSubclass = type("MyDynamicSubclass", (MyClass,), {}, my_name="Ellis")
output:
<class 'main.MyDynamicSubclass'> type
This is pretty weird since I have no idea what should I call this error.
So basically, I'm trying to input the file from another module
file1 (Input)
from file2 import Module2
class Module1():
def app_name(self,name):
p = Module2()
p.app_name(name)
def app_directory(self,directory):
p = Module2()
p.app_directory(directory)
m = Module1()
m.app_name("app")
m.app_directory("path/to/app")
file2 (getting)
class Module2():
def __init__(self):
self.name = None
self.directory = None
def app_name(self,name):
self.name = name
def app_directory(self,directory):
self.directory = directory
self.pr()
def pr(self):
print(self.name,self.directory)
After being executed, It gave me self.name = None just like what it is in init, but self.directory is what I typed in. I spent hours but still can't figure out what is the problem, I really need help.
I think this is pretty normal, you are not keeping track of p created in Module1 app_name, In other words, you are creating 2 separate objects:
If you want p you should do this:
from file2 import Module2
class Module1():
def app_name(self,name):
self.p =Module2()
self.p.app_name(name)
def app_directory(self,directory):
# p = Module2()
self.p.app_directory(directory)
m = Module1()
m.app_name("app")
m.app_directory("path/to/app")
return :
app path/to/app
How to get the name of parent object in Python code for which is current documentation build for? I mean how to get name of class "ExampleCls0" in MyDirective.run()?
class ExampleCls0():
"""
.. mydirect::
"""
Lets suppose that we have Spring directive called mydirect.
And it is correctly registered in Sphinx and documentation is build for python code.
class MyDirective(Directive):
required_arguments = 0
optional_arguments = 0
has_content = True
option_spec = {}
def run(self):
env = self.state.document.settings.env
def setup(app):
app.add_directive('mydirect', MyDirective)
For build I am using:
from sphinx.cmdline import main as sphinx_main
from sphinx.ext.apidoc import main as apidoc_main
apidoc_main(["--module-first", "--force", "--full",
"--output-dir", "doc/", "."])
sphinx_main(["-b", "html", "-E",
"-c", pwd,
"doc/",
"doc_build/",
])
I do not know if name of the parent object can be accessed somewhere in Directive.run method, but I found out that it is possible to read the name later.
class SchematicLink(nodes.TextElement):
#staticmethod
def depart_html(self, node):
self.depart_admonition(node)
#staticmethod
def visit_html(self, node):
parentClsNode = node.parent.parent
assert parentClsNode.attributes['objtype'] == 'class'
assert parentClsNode.attributes['domain'] == 'py'
sign = node.parent.parent.children[0]
assert isinstance(sign, desc_signature)
absoluteName = sign.attributes['ids'][0]
print(absoluteName) # file0.ExampleCls0
self.visit_admonition(node)
class MyDirective(Directive):
required_arguments = 0
optional_arguments = 0
def run(self):
schema_node = SchematicLink()
self.state.nested_parse(self.content,
self.content_offset,
schema_node)
return [schema_node]
def setup(app):
app.add_node(SchematicLink,
html=(SchematicLink.visit_html,
SchematicLink.depart_html))
app.add_directive('mydirect', MyDirective)
And this is probably good example how NOT to do it. Code reads id from label of class doc.
I would like to get the path and the file name of my load function and pass it to my predict function
Every time I use the code self.load() I also need to call its arguments which is the path and the filename. How do I get the path and the filename that is inside my load function.
This is the screenshot of my problem
I try to run the function load inside my predict function but i need the parameters [path] and [filename]
def load(self, path, filename):
with open(os.path.join(path, filename[0])) as stream:
self.ids.image.source = filename[0]
self.dismiss_popup()
pathh = (os.path.join(path,filename[0]))
return os.path.join(path,filename[0])
def predict(self):
#need to pass the path and filename here
Use class attributes
If you put both functions inside a class (making them methods), you can set path and filename as class attributes
#!/usr/bin/env python3
class Foo:
def __init__(self):
self.path = ''
self.filename = ''
def load(self, path, filename):
self.path = path
self.filename = filename
def predict(self):
print(self.path)
print(self.filename)
foo_instance = Foo()
foo_instance.load('/test/path', 'a_file.txt')
foo_instance.predict()
Expected result:
>> '/test/path'
>> 'a_file.txt'
Use global variables
If you don't want to use a class, you can use the global keyword to enable you to modify a variable is scoped higher than the function.
For example:
#!/usr/bin/env python3
path_outer_scope = ''
filename_outer_scope = ''
def load(self, path, filename):
global path_outer_scope
global filename_outer_scope
path_outer_scope = path
filename_outer_scope = filename
def predict(self):
print(path_outer_scope)
print(filename_outer_scope)
load('/test/path', 'a_file.txt')
predict()
Expected result:
>> '/test/path'
>> 'a_file.txt'
If you did not use the global keyword, I would expect to see
>> ''
>> ''
Which should I use?
Placing the functions inside a class is 'cleaner code' because the variables are still restricted to that class, and are not available to functions that don't need them. They are also namespaced within the class so there is less chance of a name collision.
You can declare empty strings on the top of your functions and when load() is called assign the values:
pth = ""
fname = ""
def load(self, path, filename):
pth = path
fname = filename
# your code here
def predict(self):
# use pth and fname here
I want to create my own logging class: which writes some data to a text file.
For this I have made a class mylog.py
I want to be able to create an instance object of the mylog.py class an pass the instance object as a paremeter to the other classes I have written.
However when I try to access the mylog object using the self notation and without using the self notation I am having issues.
The issue is that when I refer to the mylog object in the startup class and use self.log = logger this doesn't work to use the methods of the mylog class like self.log.write() nor does setting logobj to a variable without self and passing that in.
My mylog.py class
import datetime
import os
class logtextfile(object):
def __init__(self, name):
self.name = name
def __str__(self):
return "{} ".format(self.__class__.__name__)
def write(self,**kwargs):
"""Writes a log message to a user specified file which indicates the action takes and if it was successful"""
self.file = kwargs.get('file',"log.txt")
self.loglevel = kwargs.get('loglevel',"critical")
self.logmessage = kwargs.get('logmessage',"error")
self.success = kwargs.get('success',False)
self.class_name = kwargs.get('class',str("{}".format(self.__class__.__name__)))
self.output = ", ".join([str(datetime.datetime.now().replace(second=0,microsecond=0)),self.class_name,str(self.logmessage),str(self.success),str("\n")])
for key, value in kwargs.items():
setattr(self,key,value)
f = open(str(self.file),"a")
f.write(self.output)
f.close()
def now(self, filename, openas, data):
"""Creates a log file with todays date and time"""
fmt='%Y-%m-%d-%H-%M-%S_{fname}'
fn = datetime.datetime.now().strftime(fmt).format(fname=filename)
f = open(str(fn),openas)
f.write(data + "\n")
f.close()
My startup class
import pandas as pd
import numpy as np
from pandas_datareader import data as web
import datetime
import requests
import lxml
from IPython.display import clear_output
import time
import timeit
from bs4 import BeautifulSoup
import re
import os
import sqlite3
from sqlalchemy import create_engine # database connection
from zenlog import log
class company(object):
def __init__(self, name, logobj):
self.name = name
logger = logobj
def __str__(self):
return "{} ".format(self.__class__.__name__)
def listed(self):
try:
#all companies on asx downloaded from asx website csv
self.function_name = str("{}".format(self.__class__.__name__))
df = pd.read_csv('http://asx.com.au/asx/research/ASXListedCompanies.csv', skiprows=1)
df.columns = ["company","asx_code","industry"]
df["yahoo_code"] = df["asx_code"]+".AX"
message = "succesfully downloaded ASXListedCompanies.csv"
logger.write(file="asx_module_log.txt",logmessage=message,success=True)
return df
except:
message = "ASXListedCompanies.csv could not be retrieved, the website is unavailable"
try:
logger.write(file="asx_module_log.txt",logmessage=message)
except:
log.critical(message)
def valid(self):
try:
df = self.listed()
return df[(df["industry"]!= "Not Applic") & (df["industry"]!="Class Pend")]
except:
message = "Could not retrieve listed companies object with pandas dataframe"
try:
logfile.write(file="asx_module_log.txt",logmessage=message)
except:
log.critical(message)
def invalid(self):
try:
df = self.listed()
return df[(df["industry"]=="Not Applic") | (df["industry"]=="Class Pend")]
except:
message = "Could not retrieve listed companies object with pandas dataframe"
try:
logfile.write(file="asx_module_log.txt",logmessage=message)
except:
log.critical(message)
my code to create an instance of mylog and pass it to the startup class so that it can log to the textfile.
import mylog
import startup
logger = mylog.logtextfile(name="mylogfile")
c = startup.company(name="mycompany",logobj=logger)
df = c.invalid()
df.head()
I can't test your company class: I don't have most of those 3rd-party modules. However, it's generally a bad idea to have "naked" except clauses. Use named exceptions, otherwise you may be catching things that you don't expect.
Anyway, here's a short demo of using your logger in an instance of another class.
import datetime
class LogTextfile(object):
def __init__(self, name):
self.name = name
def __str__(self):
return "{} ".format(self.__class__.__name__)
def write(self, **kwargs):
""" Writes a log message to a user specified file which
indicates the action takes and if it was successful
"""
self.file = kwargs.get('file', "log.txt")
self.loglevel = kwargs.get('loglevel', "critical")
self.logmessage = kwargs.get('logmessage', "error")
self.success = kwargs.get('success', False)
self.class_name = kwargs.get('class', str("{}".format(self.__class__.__name__)))
self.output = ", ".join([str(datetime.datetime.now().replace(second=0, microsecond=0)),
self.class_name, str(self.logmessage), str(self.success), str("\n")])
for key, value in kwargs.items():
setattr(self, key, value)
f = open(str(self.file), "a")
f.write(self.output)
f.close()
def now(self, filename, openas, data):
"""Creates a log file with todays date and time"""
fmt = '%Y-%m-%d-%H-%M-%S_{fname}'
fn = datetime.datetime.now().strftime(fmt).format(fname=filename)
f = open(str(fn), openas)
f.write(data + "\n")
f.close()
class Test(object):
def __init__(self, logger):
self.logger = logger
def logtest(self, message):
self.logger.write(logmessage=message)
logger = LogTextfile(name="mylogfile")
logger.write(logmessage='This is a test')
t = Test(logger)
t.logtest('Message from Test')
contents of "log.txt"
2017-05-04 22:40:00, LogTextfile, This is a test, False,
2017-05-04 22:40:00, LogTextfile, Message from Test, False,
Simply:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
class A(object):
def __init__(self, x=None):
self.x = x
class B(object):
def __init__(self, a):
if (isinstance(a, A)):
self.x = a.x
else:
self.x = 0
if __name__ == "__main__":
a = A(10)
b = B(a)