Unable to debug the syntax error and need some asisstance - python-3.6

I am learing Python3.6 and spent a long time looking at this code to debug a syntax error occurring in the allcoate_seat function, position "if row not in rows:" and wanted to share this and find out the reason. I am still building the code and stuck at this position.
Code snippet:
class Flight:
def __init__(self, fnumber, aircraft):
if not fnumber[:2].isalpha():
raise ValueError ("No airline code in {}".format(fnumber))
if not fnumber[:2].isupper():
raise ValueError ("Invalid airline code in {}".format(fnumber))
if not (fnumber[2:].isdigit() and int(fnumber[2:]))<9999:
raise ValueError ("Invalid route in {}".format(fnumber))
self.fnumber=fnumber
self.aircraft=aircraft
rows, seats = aircraft.seating_plan()
self.seating=[None] + [{letter:None for letter in seats} for _ in rows]
def fnumber (self):
return self.fnumber
def airline(self):
return self.fnumber[:2]
def aircraft_model(self):
return self.aircraft.model()
def allcoate_seat(self, seat, passenger):
rows, seat_letters=self._aircraft.seating_plan()
letter=seat[-1]
if letter not in seat_letters:
raise ValueError ('Invalid seat letters {}'.format(letter))
row_text=seat[:-1]
try:
row=int(row_text)
except ValueError:
raise ValueError('Invalid seat row {}'.format(row_text)
if row not in rows:
raise ValueError ('Invalid row number {}'.format(row))
if self._seating[row][letter] is not None:
raise ValueError ('Seat already allocated {}'.format(seat))
self._seating[row][letter]=passenger
class Aircraft:
def __init__(self, registration, model, num_rows, num_seats_per_row):
self._registration=registration
self._model=model
self._num_rows=num_rows
self._num_seats_per_row=num_seats_per_row
def registration(self):
return self._registration
def model(self):
return self._model
def seating_plan(self):
return(range(1,self._num_rows+1),'ABCDEFGHJ'[:self._num_seats_per_row])
f1= Flight('TA098', Aircraft('TA008','AirbusA380',10,5))
print(f1.fnumber, f1.aircraft_model(), f1.airline(), pp(f1.seating))

Related

Airflow timetable that combines multiple cron expressions?

I have several cron expressions that I need to apply to a single DAG. There is no way to express them with one single cron expression.
Airflow 2.2 introduced Timetable. Is there an implementation that takes a list of cron expressions?
I was looking for the same thing, but didn't find anything. It would be nice if a standard one came with Airflow.
Here's a 0.1 version that I wrote for Airflow 2.2.5.
# This file is <airflow plugins directory>/timetable.py
from typing import Any, Dict, List, Optional
import pendulum
from croniter import croniter
from pendulum import DateTime, Duration, timezone, instance as pendulum_instance
from airflow.plugins_manager import AirflowPlugin
from airflow.timetables.base import DagRunInfo, DataInterval, TimeRestriction, Timetable
from airflow.exceptions import AirflowTimetableInvalid
class MultiCronTimetable(Timetable):
valid_units = ['minutes', 'hours', 'days']
def __init__(self,
cron_defs: List[str],
timezone: str = 'Europe/Berlin',
period_length: int = 0,
period_unit: str = 'hours'):
self.cron_defs = cron_defs
self.timezone = timezone
self.period_length = period_length
self.period_unit = period_unit
def infer_manual_data_interval(self, run_after: DateTime) -> DataInterval:
"""
Determines date interval for manually triggered runs.
This is simply (now - period) to now.
"""
end = run_after
if self.period_length == 0:
start = end
else:
start = self.data_period_start(end)
return DataInterval(start=start, end=end)
def next_dagrun_info(
self,
*,
last_automated_data_interval: Optional[DataInterval],
restriction: TimeRestriction) -> Optional[DagRunInfo]:
"""
Determines when the DAG should be scheduled.
"""
if restriction.earliest is None:
# No start_date. Don't schedule.
return None
is_first_run = last_automated_data_interval is None
if is_first_run:
if restriction.catchup:
scheduled_time = self.next_scheduled_run_time(restriction.earliest)
else:
scheduled_time = self.previous_scheduled_run_time()
if scheduled_time is None:
# No previous cron time matched. Find one in the future.
scheduled_time = self.next_scheduled_run_time()
else:
last_scheduled_time = last_automated_data_interval.end
if restriction.catchup:
scheduled_time = self.next_scheduled_run_time(last_scheduled_time)
else:
scheduled_time = self.previous_scheduled_run_time()
if scheduled_time is None or scheduled_time == last_scheduled_time:
# No previous cron time matched,
# or the matched cron time was the last execution time,
scheduled_time = self.next_scheduled_run_time()
elif scheduled_time > last_scheduled_time:
# Matched cron time was after last execution time, but before now.
# Use this cron time
pass
else:
# The last execution time is after the most recent matching cron time.
# Next scheduled run will be in the future
scheduled_time = self.next_scheduled_run_time()
if scheduled_time is None:
return None
if restriction.latest is not None and scheduled_time > restriction.latest:
# Over the DAG's scheduled end; don't schedule.
return None
start = self.data_period_start(scheduled_time)
return DagRunInfo(run_after=scheduled_time, data_interval=DataInterval(start=start, end=scheduled_time))
def data_period_start(self, period_end: DateTime):
return period_end - Duration(**{self.period_unit: self.period_length})
def croniter_values(self, base_datetime=None):
if not base_datetime:
tz = timezone(self.timezone)
base_datetime = pendulum.now(tz)
return [croniter(expr, base_datetime) for expr in self.cron_defs]
def next_scheduled_run_time(self, base_datetime: DateTime = None):
min_date = None
tz = timezone(self.timezone)
if base_datetime:
base_datetime_localized = base_datetime.in_timezone(tz)
else:
base_datetime_localized = pendulum.now(tz)
for cron in self.croniter_values(base_datetime_localized):
next_date = cron.get_next(DateTime)
if not min_date:
min_date = next_date
else:
min_date = min(min_date, next_date)
if min_date is None:
return None
return pendulum_instance(min_date)
def previous_scheduled_run_time(self, base_datetime: DateTime = None):
"""
Get the most recent time in the past that matches one of the cron schedules
"""
max_date = None
tz = timezone(self.timezone)
if base_datetime:
base_datetime_localized = base_datetime.in_timezone(tz)
else:
base_datetime_localized = pendulum.now(tz)
for cron in self.croniter_values(base_datetime_localized):
prev_date = cron.get_prev(DateTime)
if not max_date:
max_date = prev_date
else:
max_date = max(max_date, prev_date)
if max_date is None:
return None
return pendulum_instance(max_date)
def validate(self) -> None:
if not self.cron_defs:
raise AirflowTimetableInvalid("At least one cron definition must be present")
if self.period_unit not in self.valid_units:
raise AirflowTimetableInvalid(f'period_unit must be one of {self.valid_units}')
if self.period_length < 0:
raise AirflowTimetableInvalid(f'period_length must not be less than zero')
try:
self.croniter_values()
except Exception as e:
raise AirflowTimetableInvalid(str(e))
#property
def summary(self) -> str:
"""A short summary for the timetable.
This is used to display the timetable in the web UI. A cron expression
timetable, for example, can use this to display the expression.
"""
return ' || '.join(self.cron_defs) + f' [TZ: {self.timezone}]'
def serialize(self) -> Dict[str, Any]:
"""Serialize the timetable for JSON encoding.
This is called during DAG serialization to store timetable information
in the database. This should return a JSON-serializable dict that will
be fed into ``deserialize`` when the DAG is deserialized.
"""
return dict(cron_defs=self.cron_defs,
timezone=self.timezone,
period_length=self.period_length,
period_unit=self.period_unit)
#classmethod
def deserialize(cls, data: Dict[str, Any]) -> "MultiCronTimetable":
"""Deserialize a timetable from data.
This is called when a serialized DAG is deserialized. ``data`` will be
whatever was returned by ``serialize`` during DAG serialization.
"""
return cls(**data)
class CustomTimetablePlugin(AirflowPlugin):
name = "custom_timetable_plugin"
timetables = [MultiCronTimetable]
To use it, you provide a list of cron expressions, optionally a timezone string, optionally a period length and period unit.
For my use case I don't actually need the period length + unit, which are used to determine the DAG's data_interval. You can just leave them at the default value of 0 minutes, if your DAG doesn't care about the data_interval.
I tried to imitate standard schedule_interval behaviour. For example if catchup = False and the DAG could have potentially been triggered several times since the last run (for whatever reason, for example the DAG ran longer than expected, or the scheduler wasn't running, or it's the DAG's very first time being scheduled), then the DAG will be scheduled to run for the latest previous matching time.
I haven't really tested it with catchup = True, but in theory it would run for every matching cron time since the DAG's start_date (but only once per distinct time, for example with */30 * * * * and 0 * * * * the DAG would run twice per hour, not three times).
Example DAG file:
from time import sleep
import airflow
from airflow.operators.python import PythonOperator
import pendulum
from timetable import MultiCronTimetable
def sleepy_op():
sleep(660)
with airflow.DAG(
dag_id='timetable_test',
start_date=pendulum.datetime(2022, 6, 2, tz=pendulum.timezone('America/New_York')),
timetable=MultiCronTimetable(['*/5 * * * *', '*/3 * * * fri,sat', '1 12 3 * *'], timezone='America/New_York', period_length=10, period_unit='minutes'),
catchup=False,
max_active_runs=1) as dag:
sleepy = PythonOperator(
task_id='sleepy',
python_callable=sleepy_op
)

tkinter callback through an error: "Index 0 out of range"

I searched for hours what the heck is the reason for this error message:
I have a search entry, which update a listbox depending on my search with a callback function:
Listbox:
self.name_search=tk.StringVar()
self.name_search.trace_add('write', self.my_callback)
self.e_name_search_text = tk.Label(search_f, text="Name: ").grid(row=0, column=0, padx=10, pady=5, sticky='E')
self.e_name_search = ttk.Entry(search_f, width = 35, textvariable=self.name_search)
self.e_name_search.grid(row=0, column=1, padx=5, pady=5, sticky='W')
self.lbox = tk.Listbox(search_f, width=35, height=8)
self.lbox.bind("<Double-Button-1>", self.show_name_search)
self.lbox.bind('<Return>', self.show_name_search)
self.scrollbar = tk.Scrollbar(search_f)
self.lbox.grid(row=1, column=1, rowspan=3, padx=10, pady=1)
self.lbox.config(yscrollcommand = self.scrollbar.set)
self.scrollbar.grid(row=1, column=2, rowspan=3, padx=1, pady=1, sticky='ns')
self.scrollbar.config(command=self.lbox.yview)
So If I type my search, the listbox show me a reduced list of values out of my sqlite database, I am interessed in. If I select one with dobble click. Another sqlite query update my comboboxes.
If I select one I get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "D:\... name.py", line 337, in show_name_search
self.e_fax.current(0)
File "C:\Python38-32\lib\tkinter\ttk.py", line 717, in current
return self.tk.call(self._w, "current", newindex)
_tkinter.TclError: Index 0 out of range
Line 337 comes from another function:
def show_name_search(self, event):
self.clear_field()
widget = event.widget
selection = widget.curselection()
indName = widget.get(selection[0])
print(indName)
print("selktierter Wert: {}".format(indName))
self.realName.set(indName)
connection = sqlite3.connect(select_connect_db)
print('Database connected.')
with connection:
cursor = connection.cursor()
cursor.execute("SELECT number, type, prio, id, uniqueid FROM numbers WHERE realName=?;",(indName,))
data = cursor.fetchall()
print(data)
for row in data:
if row[1] == 'home':
self.phone_home.append(row[0])
print('HOME:',self.phone_home)
if row[1] == 'mobile':
self.mobile.append(row[0])
print('Mobile:',self.mobile)
if row[1] == 'work':
self.business.append(row[0])
print(row[0])
print('WORK:',self.business)
if row[1] == 'fax_work':
self.fax.append(row[0])
print(row[0])
print('FAX_WORK:',self.fax)
self.uid_name.set(row[4])
if len(self.phone_home) != 0:
self.e_phone['values'] = self.phone_home
self.e_phone.current(0)
if len(self.mobile) != 0:
self.e_mobile['values'] = self.mobile
self.e_mobile.current(0)
if len(self.business) != 0:
self.e_business['values'] = self.business # Set the value to the new list
self.e_business.current(0) # Set the first item of the list as current item
if len(self.business) != 0:
self.e_fax['values'] = self.fax
self.e_fax.current(0) ### Line 337 - No entry for this value in my sqlite database
Any idea, what I can search for ?
So self.e_faxseems like a ttk.Combobox to me. Consider this code here:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
values = []
lb = ttk.Combobox(root,values=values)
lb.current(0)
lb.pack()
root.mainloop()
it throughs the same Error:
_tkinter.TclError: Index 0 out of range
and the reason is the list values is empty, insert any regular string in it and it works.
Make sure if you want to set default value that there is an value.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
values = ['see']
lb = ttk.Combobox(root,values=values)
lb.current(0)
lb.pack()
root.mainloop()

python unittest error and using patch from unittest.mock

I have two python files the first one is named employee.py and this is its code
import requests
class Employee:
"""A sample Employee class"""
raise_amt = 1.05
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
#property
def email(self):
return '{}.{}#email.com'.format(self.first, self.last)
#property
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amt)
def monthly_schedule(self, month):
response = requests.get(f'http://company.com/{self.last}/{month}')
if response.ok:
return response.text
else:
return 'Bad Response!'
The other file is named test_employee.py
and this is its code
import unittest
from unittest.mock import patch
from employee import Employee
class TestEmployee(unittest.TestCase):
#classmethod
def setUpClass(cls):
print('setupClass')
#classmethod
def tearDownClass(cls):
print('teardownClass')
def setUp(self):
print('setUp')
self.emp_1 = Employee('Corey', 'Schafer', 50000)
self.emp_2 = Employee('Sue', 'Smith', 60000)
def tearDown(self):
print('tearDown\n')
def test_email(self):
print('test_email')
self.assertEqual(self.emp_1.email, 'Corey.Schafer#email.com')
self.assertEqual(self.emp_2.email, 'Sue.Smith#email.com')
self.emp_1.first = 'John'
self.emp_2.first = 'Jane'
self.assertEqual(self.emp_1.email, 'John.Schafer#email.com')
self.assertEqual(self.emp_2.email, 'Jane.Smith#email.com')
def test_fullname(self):
print('test_fullname')
self.assertEqual(self.emp_1.fullname, 'Corey Schafer')
self.assertEqual(self.emp_2.fullname, 'Sue Smith')
self.emp_1.first = 'John'
self.emp_2.first = 'Jane'
self.assertEqual(self.emp_1.fullname, 'John Schafer')
self.assertEqual(self.emp_2.fullname, 'Jane Smith')
def test_apply_raise(self):
print('test_apply_raise')
self.emp_1.apply_raise()
self.emp_2.apply_raise()
self.assertEqual(self.emp_1.pay, 52500)
self.assertEqual(self.emp_2.pay, 63000)
def test_monthly_schedule(self):
with patch('employee.requests.get') as mocked_get:
mocked_get.return_value.ok = True
mocked_get.return_value.text = 'Success'
schedule = self.emp_1.monthly_schedule('May')
mocked_get.assert_called_with('http://company.com/Schafer/May')
self.assertEqual(schedule,'Success')
if __name__ == '__main__':
unittest.main()
when I run test_employee.py, I get this error
ModuleNotFoundError: No module named 'employee.requests'; 'employee' is not a package
The code runs well if you delete the function test_monthly_schedule from test_employee.py
and delete monthly_schedule from employee.py
also I do not know if that will make a difference, but I use python 3.8. Also, I'm using Mac

tuple index out of range for printing a index value

While executing the following code i'm getting below error, Just for information matchObj here returns a tuple value ..
$ ./ftpParser3_re_dup.py
Traceback (most recent call last):
File "./ftpParser3_re_dup.py", line 13, in <module>
print("{0:<30}{1:<20}{2:<50}{3:<15}".format("FTP ACCOUNT","Account Type","Term Flag"))
IndexError: tuple index out of range
Code is below:
from __future__ import print_function
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
import re
with open('all_adta', 'r') as f:
for line in f:
line = line.strip()
data = f.read()
# Making description & termflag optional in the regex pattern as it's missing in the "data_test" file with several occurrences.
regex = (r"dn:(.*?)\nftpuser: (.*)\n(?:description:* (.*))?\n(?:termflag:* (.*))")
matchObj = re.findall(regex, data)
print("{0:<30}{1:<20}{2:<50}{3:<15}".format("FTP ACCOUNT","Account Type","Term Flag"))
print("{0:<30}{1:<20}{2:<50}{3:<15}".format("-----------","------------","--------"))
for index in matchObj:
index_str = ' '.join(index)
new_str = re.sub(r'[=,]', ' ', index_str)
new_str = new_str.split()
# In below print statement we are using "index[2]" as index is tuple here, this is because
# findall() returns the matches as a list, However with groups, it returns it as a list of tuples.
print("{0:<30}{1:<20}{2:<50}{3:<15}".format(new_str[1],new_str[8],index[2],index[3]))
In the line print("{0:<30}{1:<20}{2:<50}{3:<15}".format("FTP ACCOUNT","Account Type","Term Flag")) you have mentioned 4 indices but given only 3 i.e. "FTP ACCOUNT","Account Type","Term Flag"
Remove the 4th index or add a new one

Error in mapping DataFrame for keyword in ipython

I have collected tweets and wish to add a column named taliban that maps (true/false) for the word (Taliban/taliban) present in the tweet. Please see the code and its error.
tweets = pd.DataFrame()
from pandas.io.json import json_normalize
tweets = json_normalize(tweet_data)[["text", "lang", "place.country","created_at", \
"coordinates", "user.location"]]
The code to define word is as follows:
#definition for collecting keyword.
def word_in_text(word, text):
word = word.lower()
text = text.lower()
match = re.search(word, text)
if match:
return True
return False
Then I run this query:
tweets['Taliban'] = tweets['text'].apply(lambda tweet: word_in_text('Taliban', tweet))
I get the following error:
AttributeError Traceback (most recent call last)
<ipython-input-16-17bcf7fbf866> in <module>()
----> 1 tweets['Taliban'] = tweets['text'].apply(lambda tweet: word_in_text('Taliban', tweet))
/usr/lib64/python2.7/site-packages/pandas/core/series.pyc in apply(self, func, convert_dtype, args, **kwds)
2167 values = lib.map_infer(values, lib.Timestamp)
2168
-> 2169 mapped = lib.map_infer(values, f, convert=convert_dtype)
2170 if len(mapped) and isinstance(mapped[0], Series):
2171 from pandas.core.frame import DataFrame
pandas/src/inference.pyx in pandas.lib.map_infer (pandas/lib.c:62578)()
<ipython-input-16-17bcf7fbf866> in <lambda>(tweet)
----> 1 tweets['Taliban'] = tweets['text'].apply(lambda tweet: word_in_text('Taliban', tweet))
<ipython-input-15-56228996ad5c> in word_in_text(word, text)
2 def word_in_text(word, text):
3 word = word.lower()
----> 4 text = text.lower()
5 match = re.search(word, text)
6 if match:
AttributeError: 'float' object has no attribute 'lower'
In [ ]:
I have tried this modification:
#definition for collecting keyword.
def word_in_text(word, text):
word = word.lower()
if type(text) is str:
return text.lower()
match = re.search(word, text)
if match:
return True
return False
to be used in:
tweets['taliban'] = tweets['text'].apply(lambda tweet: word_in_text('taliban', tweet))
But the error given is:
UnboundLocalError: local variable 'match' referenced before assignment

Resources