How Can I Get A Dictionary Value From Python? - python-3.x

I was trying to convert a look up today to a data dictionary...for performance reasons...
It's almost working...Except that it's duplicating the entries on my output...
Here is my code in question...
class Calendar(HTMLCalendar):
def __init__(self, year=None, month=None, user=None):
self.user = user
self.year = year
self.month = month
super(Calendar, self).__init__()
# formats a day as a td
# filter events by day
def formatday(self, day, requests):
requests_per_day = DailyPlannerRequest.objects.filter(Q(created_by=self.user)).distinct().order_by('start_time')
daily_planner_events1 = []
for requests in requests_per_day:
requests_per_day_dict = model_to_dict(requests)
daily_planner_events1.append(requests_per_day_dict)
daily_planner_events1 = dict()
events = add_event_dates(requests_per_day)
all_event_dates = []
for event in events:
for date in event.dates:
if date not in all_event_dates and date.month == self.month and date.year == self.year:
all_event_dates.append(date)
for event in events:
for date in event.dates:
if date in all_event_dates and date not in daily_planner_events1 and date.month == self.month and date.year == self.year:
daily_planner_events1[date] = [event]
else:
if date.month == self.month and date.year == self.year:
daily_planner_events1[date].append(event)
# daily_planner_events[date].append(events)
d = ''
for requests in requests_per_day:
for event in daily_planner_events1:
if event.day == day:
d += f'<li> {requests.get_html_url} </li>'
if day != 0:
return f"<td><span class='date'>{day}</span><ul> {d} </ul></td>"
return '<td></td>'
The code above works...Except it's giving me incorrect output...The problem piece in particular is this...
for requests in requests_per_day:
for event in daily_planner_events1:
if event.day == day:
d += f'<li> {requests.get_html_url} </li>'
It's not narrowing down the output specific enough.
I've played with this all afternoon..and the other version that actually kinda works is...
for event in daily_planner_events1:
if event.day == day:
d += f'<li> {event.get_html_url} </li>'
If I remove the request piece and change request to event it works exactly how I want except the get_html_url piece now doesn't work. It won't access the ID from the dictionary and as far as I can tell the way that I'm comparing the events...it doesn't have the ID information to provide. What am I doing wrong?
Thanks in advance for any thoughts.

Your code is very convoluted and could probably be made a whole lot simpler. For example, daily_planner_events1 is used as a list and then replaced with a dict() before you do anything with it? It's very hard to review your question because your code isn't straightforward and some of the functions aren't included, like add_event_dates and get_html_url.
To try and answer your question, the most likely reason why you are struggling to get your intended results is because your final nested for-loop aren't connected to each other properly, i.e. they aren't looping on related objects. Hence removing the outer for-loop has helped, presumably the reason why you aren't getting the output you want is because event.get_html_url isn't returning the right thing.
I went through all your code to try and figure out what's happening and think it could be far more succinct. As I mentioned already, I don't know what some of the functions do and I suspect there is a different model somewhere, so some things might need to change:
def formatday(self, day, requests):
# if the day is zero then return an empty table cell, don't run through any more code
if day == 0:
return '<td></td>'
# Q expression isn't needed here
requests_per_day = DailyPlannerRequest.objects.filter(created_by=self.user)...
# repeated checks of self.month and self.year can be done in an ORM filter
all_event_dates = SomeEventModel.filter(
dates__month=self.month,
dates__year=self.year
)
# no idea what this does?
events = add_event_dates(requests_per_day)
d = ''
# remove the if-statement and use another filter
for event in all_event_dates.filter(day=day):
d += f'<li> {event.get_html_url} </li>'
# return your table cell with the list appended
return f"<td><span class='date'>{day}</span><ul> {d} </ul></td>"

After a week of trial and error...it turns out I needed to add a .date() to the loop to make it work.
for event in requests_per_day:
for request in daily_planner_events1:
if request.day == day and request == event.start_time.date():
d += f'<li> {event.get_html_url} </li>'

Related

How to update Progressbar in PyQT through QThread which calls another function

I am quite new to PyQT. I am learning how to make a Progressbar and update it as my algorithm progresses. I have been able to make a Basic Progressbar that updates itself using this link: Python pyqt pulsing progress bar with multithreading
The problem is, I need to do the same for my algorithm and that algorithm has a different function and can not be written inside the run function of QThread.
This is my code for the QThread class, (same as given in above link)
class External(QThread):
countChanged = pyqtSignal(int)
def run(self):
count = 0
while count < 100:
count += 1
time.sleep(1)
self.countChanged.emit(count)
And this is the code for my Progressbar,
def generate_timetable(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.ui.progressBar.setValue(value)
Now, this is kind of a pseudocode of my algorithm function (this function will basically replace the time.sleep(1) function)
def algorithm():
fh = False
best_solution = None
count = 1
best_fitness = 100000 # any huge number
while fh is False:
fh = True
solution, solution_fitness = another_function()
if solution_fitness < best_fitness:
best_solution = solution
best_fitness = solution_fitness
fh = False
print("ITERATION #", count, " is OVER!")
print("Best Solution FItness: ", best_fitness)
count += 1
return best_solution, best_fitness
What I need to do is after every iteration, my Thread class emits a signal and the best solution's fitness value is printed on my main GUI (I have a label for that) and Progressbar's value is also updated (let's say I want it to update by 1 count only, just like it is being done in the current program)
The problem however is this that I can't return the fitness value after one iteration, because if I do that, my algorithm will need to be restarted and hence I will lose my progress. But without returning the value from the function, I don't know how can I possibly know that one iteration is over so now emit the signal, update the progressbar value and also set the label value to the fitness value calculated after the iteration.
Can anyone guide me regarding this? or show me any project that has something similar to this.
I think you can get what you want by just changing your signal from pyqtSignal(int) to pyqtSignal(int, int) and then within your algorithm loop self.countChanged.emit(count, best_fitness). You could also define a second signal for the fitness if you want them separate.

How can I test a loop with multiple input calls?

I'm trying to test a fuction that dependets a of multiple user inputs to return some value.
I've already looked for multiples unswers here but none was able to resolve my problem. I saw things with parametrize, mock and monkey patch but none helped. I think a lot is because I don't clearly understood the concepts behind what was being done and I couldn't adapt to my problem. I saw suggestion of using external file for this but I don't wont to depend on that. I'm trying with pytest and python 3.7.3
The function that I want to test is something like this
def function():
usr_input = input('please enter a number: ')
while True:
if int(usr_input) < 5:
usr_input = input('please, enter a value less then 5: ')
else:
break
return usr_input
I want to know how can I pass two input values to test the function when the inserted value is not valid. Example: Send value 6 and 2, make an assert expecting value 2 and pass the test. My others tests look like this:
def test_input(monkeypatch):
monkeypatch.setattr('builtins.input', lambda x: 6)
test = function()
assert test == 2
but, for this case, they loop. It's possible to do this only with parametrize or other simple code?
EDIT
I added a int() in my "if", as wim pointed in the accepted answer, just to prevent any confusion for future readers. I'm assuming the cast is possible.
Two problems here, you need to convert the input into a number otherwise the comparison will fail, comparing a string with a number: usr_input < 5. Note that the real input will never return a number, only a string.
Once you've cleared that up, you can monkeypatch input with a callable that can return different values when called:
def fake_input(the_prompt):
prompt_to_return_val = {
'please enter a number: ': '6',
'please, enter a value less then 5: ': '2',
}
val = prompt_to_return_val[the_prompt]
return val
def test_input(monkeypatch):
monkeypatch.setattr('builtins.input', fake_input)
test = function()
assert test == 2
If you install the plugin pytest-mock, you can do this more easily with the mock API:
def test_input(mocker):
mocker.patch('builtins.input', side_effect=["6", "2"])
test = function()
assert test == 2

why my result is overriding in python

def geteta(self,b=0,etatype="schedule"):
eta_3_cuurtime = self.currtime + timedelta(hours = b)
[self.a["legdata"].get(str(i)).append({'depdetails':self.func(self.a["legdata"].get(str(i))[2],eta_3_cuurtime,etatype,self.thceta)}) if i==1 else self.a["legdata"].get(str(i)).append({'depdetails':self.func(self.a["legdata"].get(str(i))[2],self.a['legdata'].get(str(i-1))[3]['depdetails'][2])}) for i in range(1,len(self.a['legdata'])+1)]
eta1 = self.a["legdata"].get(str(len(self.a["legdata"])))[3]['depdetails'][2] #13. eta is last items depdetails [2] (available)
return eta1
def main(self):
eta3 = self.geteta()
eta4 = self.geteta(b=3)
when i am calling geteta method with different inputs my result (eta3,eta4) are same values.when i run method indiviual (comment first geteta) it is giving correct values.i know some where values are overriding but i am not able to figure out where it is.i hv struggling from couple of days for finding this but not.please help me in this

Periodically running a function in python

I have the following function that gets some data from a web page and stores in a dictionary. The time stamp as a key, and the data (list) as value.
def getData(d):
page = requests.get('http://www.transportburgas.bg/bg/%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D1%80%D0%BE%D0%BD%D0%BD%D0%BE-%D1%82%D0%B0%D0%B1%D0%BB%D0%BE')
soup = BeautifulSoup(page.content, 'html.parser')
table = soup.find_all("table", class_="table table-striped table-hover")
rows = table[0].find_all('tr')
table_head = table[0].find_all('th')
header = []
tr_l = []
rows = []
for tr in table[0].find_all('tr'):
value = tr.get_text()
rows.append(value)
time_stamp = rows[1].split("\n")[1]
data = []
for i in rows[1:]:
a = i.split("\n")
if time.strptime(a[1], '%d/%m/%Y %H:%M:%S')[:4] == time.localtime()[:4]:
data.append(int(a[3]))
else:
data.append(np.nan)
d[time_stamp] = data
The data on the web page gets updated every 5 mins. I would like to make the function run automatically every 5 min. I am trying to do it with the time.sleep and this function:
def period_fun(it):
iterations = it
while iterations != 0:
getData(dic)
time.sleep(300)
iterations = iterations -1
However, this function runs only once and I end up with only one item in the dictionary. I have tried it with a simple print (1) instead of the function and it works (1 gets printed several times), but when I implement it with the function it doesn't work.
Would really appreciate any suggestions on the functions or how I could achieve my goal!
Best regards,
Mladen
How about using some library which use cron jobs?
Schedule looks nice although it is not using cron like syntax: https://github.com/dbader/schedule

How to check all variables created by class function and use them?

In short; I started coding a few days ago and thought trying to make a simple text based adventure will let me face a lot of problems that I will encounter in other harder projects as well. My class init function produces items with some variables, one of which is it's equipment slot position [0-6]. I would like to unequip a slot, but the way I have it set up at the moment requires me to know which item is in that particular slot.
In english: unequip("mainhand"), mainhand has slotnumber 0. Get the info of all equipped items and check which one has the corresponding slotnumber, then remove that particular item.
(Some items have 2 slotnumbers ("althand") which means I will have to find a way to make sure I remove the right item from the list, but that is something I can do later). For now, I can't seem to figure out how to dynamically call items and do stuff with them.
PS. I am pretty sure I can do this in a way more phytonic manner and any suggestions are welcome, but regardless of this, I would still like to know how to dynamically call the function.
The code with which I try this:
def Unequip(Slotname): #Slotname is just a string, so I could say: unequip("Mainhand")
for count,i in enumerate(Item.slotname): #Item.slotname is a list of strings for slots which corresponds with Item.Slot which are the values determining the which slot is occupied.
if Slotname == Item.slotname[count]: #so when the name I put into the function equals the Item.slotname, I know which number in Item.Slot I need.
for items in Item: #Here we enter the problem (again, I understand that this code could be a lot better and would love some suggestions).
#Item is a object, but it's __init__ functions produces items, such as item1, item2 etc. I would like to check if any of these items is currently in my Item.Equipped and has the Item.Slot value I want to remove.
#I tried global(), locals() and dir(Item) but none give me what I need. I really hope this makes it clear.
if Item.Slot[count] == items.slot and items.name == Item.Equipped: #I need a susbtitute for the items variable which will represent item1, item2 or item3 etc. So I can do Item.Slot.remove(item2.slot).
Slot = Item.Slot.remove(items.slot)
Equipped = Item.Equipped.remove(items.name)
Player.stats = list(map(operator.sub,list(Player.stats),self.itemstats))
elif Item.Slot[i] == items.altslot and Items.name == items.Equipped:
pass
Full code (I tried using self etc, but it may not be super readable, my apologies), it includes a item.unequip function but this requires me to select the particular item instead of just the slot from which I want my item to be removed
Edit1: Removed all unneeded stuff per request:
import random
import operator
class Item:
Equipped = []
Slot = []
Inventory = []
num_of_items = 0
statnames = ["Strength", "Agility", "Dexterity", "Wisdom", "Constitution", "Intelligence"]
slotname = ["MainHand","Offhand","Head", "Necklace","Chest","Legs", "Cape" ]
def __init__(self, name, itemstats, slot, altslot = None, atk = None, Def = None):
self.itemstats = itemstats #itemstats in order: S, A, D, W, C, I
self.name = name
Item.num_of_items += 1
self.slot = slot
self.altslot = altslot
if atk != None and atk != 0:
self.atk = atk
if Def != None and Def != 0:
self.Def = Def
def Unequip(Slotname):
for count,i in enumerate(Item.slotname):
if Slotname == Item.slotname[count]:
for items in dir(Item):
if Item.Slot[count] == items.slot and items.name == Item.Equipped:
Slot = Item.Slot.remove(items.slot)
Equipped = Item.Eqiupped.remove(items.name)
Player.stats = list(map(operator.sub,list(Player.stats),self.itemstats))
elif Item.Slot[i] == items.altslot and Items.name == items.Equipped:
pass
class Player:
stats= [8,8,8,8,8,8]
item1 = Item("Sword of damaocles",[5, 1, 0,1,2,-2],0,1,20)
item2 = Item("Helmet of steel",[9,9,9,9,9,9],2,None,0,20)

Resources