Make a separate table based schedule for M 25-04B
/tmp/workspace
~/attachments
~/attachments/816a254c-6020-4e6a-84a1-577511f197c3
python -c "import pdfplumber; p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf'; pdf=pdfplumber.open(p); print('PAGES',len(pdf.pages)); [print('\\n--- PAGE',i+1,'---\\n',page.extract_text() or '') for i,page in enumerate(pdf.pages)]"
mkdir -p "/tmp/workspace/m25-04b-schedule/assets" "/tmp/workspace/m25-04b-schedule/output" && python -c "import fitz; p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf'; d=fitz.open(p); [d[i].get_pixmap(matrix=fitz.Matrix(2,2), alpha=False).save(f'/tmp/workspace/m25-04b-schedule/assets/page_{i+1}.png') for i in [2,3]]" && ls -lh "/tmp/workspace/m25-04b-schedule/assets"
python - <<'PY' import pdfplumber, json p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf' with pdfplumber.open(p) as pdf: for n in (2,3): page=pdf.pages[n] print('PAGE',n+1,'size',page.width,page.height) print('tables',len(page.find_tables())) for t in page.find_tables(): print(t.bbox, t.extract()[:3]) words=page.extract_words(use_text_flow=True, keep_blank_chars=False) for w in words: print(f"{w['text']!r} x={w['x0']:.1f}-{w['x1']:.1f} top={w['top']:.1f}-{w['bottom']:.1f}") PY
python - <<'PY' import pdfplumber p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf' with pdfplumber.open(p) as pdf: for pg in [2,3]: t=pdf.pages[pg].find_tables()[0].extract() print('\nPAGE',pg+1,'rows',len(t)) for i,row in enumerate(t): print(i,repr(row[3] if len(row)>3 else None)) PY
python - <<'PY' try: import pypdfium2 as pdfium print('pdfium yes') p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf' pdf=pdfium.PdfDocument(p) for i in (2,3): page=pdf[i] image=page.render(scale=3).to_pil() image.save(f'/tmp/workspace/m25-04b-schedule/assets/page_{i+1}.png') except Exception as e: print(type(e),e) PY ls -lh "/tmp/workspace/m25-04b-schedule/assets"
python - <<'PY' import pdfplumber p='/tmp/workspace/attachments/816a254c-6020-4e6a-84a1-577511f197c3/+2 курс 3 сем 2026-2027 222.pdf' with pdfplumber.open(p) as pdf: for pg in [2,3]: t=pdf.pages[pg].find_tables()[0].extract() print('\n--- PAGE',pg+1,'---') for i,row in enumerate(t): print(i, ' | '.join((c or '').replace('\n',' / ') for c in row)) PY
python - <<'PY' from openpyxl import Workbook, load_workbook from openpyxl.styles import Font, PatternFill, Border, Side, Alignment from openpyxl.utils import get_column_letter from openpyxl.worksheet.dimensions import ColumnDimension from openpyxl import Workbook from pathlib import Path out=Path('/tmp/workspace/m25-04b-schedule/output/M_25-04B_Schedule_2026-2027.xlsx') out.parent.mkdir(parents=True,exist_ok=True) wb=Workbook() ws=wb.active ws.title='M 25-04B' ws.sheet_view.showGridLines=False # Palette navy='17365D'; blue='1F4E78'; light_blue='D9EAF7'; pale='F3F7FB'; white='FFFFFF'; gold='FFD966'; gray='6B7280' thin=Side(style='thin',color='B7C9D6') medium=Side(style='medium',color=navy) ws.merge_cells('A1:E1') ws['A1']='CASPIAN UNIVERSITY' ws['A1'].font=Font(name='Arial',size=15,bold=True,color=white) ws['A1'].fill=PatternFill('solid',fgColor=navy) ws['A1'].alignment=Alignment(horizontal='center',vertical='center') ws.row_dimensions[1].height=27 ws.merge_cells('A2:E2') ws['A2']='M 25-04B | Class Schedule' ws['A2'].font=Font(name='Arial',size=13,bold=True,color=navy) ws['A2'].alignment=Alignment(horizontal='center',vertical='center') ws.row_dimensions[2].height=23 ws.merge_cells('A3:E3') ws['A3']='2nd Course, Semester 3, 2026-2027 Academic Year | EP 6B10124 Medicine' ws['A3'].font=Font(name='Arial',size=10,italic=True,color=gray) ws['A3'].alignment=Alignment(horizontal='center') ws.row_dimensions[3].height=18 headers=['Day','Time','Subject','Room','Period / Note'] for col,h in enumerate(headers,1): c=ws.cell(5,col,h); c.font=Font(name='Arial',size=10,bold=True,color=white); c.fill=PatternFill('solid',fgColor=blue); c.alignment=Alignment(horizontal='center',vertical='center',wrap_text=True); c.border=Border(top=medium,bottom=medium,left=thin,right=thin) ws.row_dimensions[5].height=27 rows=[ ['Monday','14:00-15:50','Microbiology','514',''], ['Monday','16:00-17:50','Pre-hospital medical care','505',''], ['Tuesday','10:00-11:50','Immunology','520','05 Oct to 12 Dec'], ['Wednesday','10:00-11:50','Histology-1','519',''], ['Thursday','10:00-11:50','Anatomy-1','501',''], ['Thursday','12:00-13:50','Foreign language (professional)','503',''], ['Friday','12:00-13:50','Biochemistry-1','513',''], ['Saturday','10:00-11:50','Physiology-1','503',''], ] for r_idx,row in enumerate(rows,6): for c_idx,val in enumerate(row,1): c=ws.cell(r_idx,c_idx,val) c.font=Font(name='Arial',size=10,color='000000') c.fill=PatternFill('solid',fgColor=pale if r_idx%2==0 else white) c.alignment=Alignment(vertical='center',horizontal='center' if c_idx in [1,2,4] else 'left',wrap_text=True) c.border=Border(top=thin,bottom=thin,left=thin,right=thin) ws.row_dimensions[r_idx].height=30 # Merge weekday cells for grouped days for start,end in [(6,7),(10,11)]: ws.merge_cells(start_row=start,start_column=1,end_row=end,end_column=1) c=ws.cell(start,1); c.alignment=Alignment(horizontal='center',vertical='center',wrap_text=True) c.fill=PatternFill('solid',fgColor=light_blue) c.font=Font(name='Arial',size=10,bold=True,color=navy) # restore borders throughout merge boundaries for rr in range(start,end+1): for cc in [1]: ws.cell(rr,cc).border=Border(top=thin,bottom=thin,left=thin,right=thin) # Apply bold style to unmerged weekday labels and rooms for r in [8,9,12,13]: ws.cell(r,1).font=Font(name='Arial',size=10,bold=True,color=navy) ws.cell(r,1).fill=PatternFill('solid',fgColor=light_blue) for r in range(6,14): ws.cell(r,4).font=Font(name='Arial',size=10,bold=True,color=navy) ws.merge_cells('A15:E15') ws['A15']='Note: Immunology runs from 05 October to 12 December. All other classes are listed as shown in the source timetable.' ws['A15'].font=Font(name='Arial',size=9,italic=True,color=gray) ws['A15'].alignment=Alignment(wrap_text=True,vertical='center') ws['A15'].fill=PatternFill('solid',fgColor='FFF2CC') ws['A15'].border=Border(top=thin,bottom=thin,left=thin,right=thin) ws.row_dimensions[15].height=30 for col,width in {'A':16,'B':16,'C':34,'D':11,'E':25}.items(): ws.column_dimensions[col].width=width ws.freeze_panes='A6' ws.auto_filter.ref='A5:E13' ws.sheet_properties.pageSetUpPr.fitToPage=True ws.page_setup.orientation='landscape'; ws.page_setup.paperSize=ws.PAPERSIZE_A4; ws.page_setup.fitToWidth=1; ws.page_setup.fitToHeight=1 ws.print_area='A1:E15' ws.oddFooter.center.text='M 25-04B | Page &P of &N' ws.oddFooter.center.size=8 wb.save(out) # Verify exact schedule values and merged ranges check=load_workbook(out,data_only=False) s=check['M 25-04B'] assert s['C6'].value=='Microbiology' and s['C13'].value=='Physiology-1' assert s['E8'].value=='05 Oct to 12 Dec' assert len(s.merged_cells.ranges)>=5 print(out, out.stat().st_size, s.max_row, s.max_column) PY
Quick answer
M 25 04B Schedule 2026 2027
Spreadsheet · XLSX
Create a printable PDF version of this schedule
/tmp/workspace
Caspian University official schedule Medicine 2026 2027
mkdir -p "/tmp/workspace/m25-04b-schedule/output" && python - <<'PY' from reportlab.lib import colors from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.lib.pagesizes import A4, landscape from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import mm from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, KeepTogether from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics from pathlib import Path out=Path('/tmp/workspace/m25-04b-schedule/output/M_25-04B_Schedule_2026-2027.pdf') page=landscape(A4) navy=colors.HexColor('#17365D'); blue=colors.HexColor('#1F4E78'); pale=colors.HexColor('#F3F7FB'); dayfill=colors.HexColor('#D9EAF7'); note=colors.HexColor('#FFF2CC'); gray=colors.HexColor('#5B6573') styles=getSampleStyleSheet() title=ParagraphStyle('title', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=17, leading=21, textColor=navy, alignment=TA_CENTER, spaceAfter=2) sub=ParagraphStyle('sub', parent=styles['Normal'], fontName='Helvetica', fontSize=10, leading=13, textColor=gray, alignment=TA_CENTER, spaceAfter=9) head=ParagraphStyle('head', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=9.5, leading=11, textColor=colors.white, alignment=TA_CENTER) body=ParagraphStyle('body', parent=styles['Normal'], fontName='Helvetica', fontSize=10.2, leading=13, textColor=colors.black, alignment=TA_LEFT) center=ParagraphStyle('center', parent=body, alignment=TA_CENTER) day=ParagraphStyle('day', parent=body, fontName='Helvetica-Bold', textColor=navy, alignment=TA_CENTER) room=ParagraphStyle('room', parent=body, fontName='Helvetica-Bold', textColor=navy, alignment=TA_CENTER) note_style=ParagraphStyle('note', parent=styles['Normal'], fontName='Helvetica-Oblique', fontSize=9, leading=12, textColor=gray, alignment=TA_LEFT) # Data reconstructed from source timetable classes=[ ('Monday','14:00-15:50','Microbiology','514',''), ('Monday','16:00-17:50','Pre-hospital medical care','505',''), ('Tuesday','10:00-11:50','Immunology','520','05 Oct to 12 Dec'), ('Wednesday','10:00-11:50','Histology-1','519',''), ('Thursday','10:00-11:50','Anatomy-1','501',''), ('Thursday','12:00-13:50','Foreign language (professional)','503',''), ('Friday','12:00-13:50','Biochemistry-1','513',''), ('Saturday','10:00-11:50','Physiology-1','503',''), ] data=[[Paragraph('<b>Day</b>',head),Paragraph('<b>Time</b>',head),Paragraph('<b>Subject</b>',head),Paragraph('<b>Room</b>',head),Paragraph('<b>Period / Note</b>',head)]] for d,t,s,r,n in classes: data.append([Paragraph(d,day),Paragraph(t,center),Paragraph(s,body),Paragraph(r,room),Paragraph(n,body)]) # Single page, printable table col_widths=[37*mm,39*mm,92*mm,24*mm,62*mm] t=Table(data, colWidths=col_widths, repeatRows=1, hAlign='CENTER', rowHeights=[10*mm]+[14*mm]*len(classes)) style=[ ('BACKGROUND',(0,0),(-1,0),blue),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('GRID',(0,0),(-1,-1),0.45,colors.HexColor('#B7C9D6')), ('LINEABOVE',(0,0),(-1,0),1.0,navy),('LINEBELOW',(0,0),(-1,0),1.0,navy), ('BACKGROUND',(0,1),(-1,-1),colors.white), ] for i in range(1,len(classes)+1): if i%2==0: style.append(('BACKGROUND',(0,i),(-1,i),pale)) style.append(('BACKGROUND',(0,i),(0,i),dayfill)) t.setStyle(TableStyle(style)) story=[Spacer(1,6*mm),Paragraph('CASPIAN UNIVERSITY', title),Paragraph('M 25-04B | Class Schedule', title),Paragraph('2nd Course, Semester 3, 2026-2027 Academic Year | EP 6B10124 Medicine',sub),t,Spacer(1,6*mm)] nt=Table([[Paragraph('<b>Note:</b> Immunology runs from 05 October to 12 December. All other classes are listed as shown in the source timetable.',note_style)]],colWidths=[254*mm]) nt.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),note),('BOX',(0,0),(-1,-1),0.5,colors.HexColor('#D8C27A')),('LEFTPADDING',(0,0),(-1,-1),8),('RIGHTPADDING',(0,0),(-1,-1),8),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)])) story += [nt,Spacer(1,6*mm),Paragraph('Prepared from the official 2026-2027 timetable.', ParagraphStyle('foot',parent=note_style,alignment=TA_CENTER,fontSize=8))] doc=SimpleDocTemplate(str(out),pagesize=page,rightMargin=18*mm,leftMargin=18*mm,topMargin=10*mm,bottomMargin=11*mm,title='M 25-04B Schedule 2026-2027',author='Caspian University') doc.build(story) print(out, out.stat().st_size) PY python - <<'PY' from pypdf import PdfReader p='/tmp/workspace/m25-04b-schedule/output/M_25-04B_Schedule_2026-2027.pdf' r=PdfReader(p) text='\n'.join(page.extract_text() or '' for page in r.pages) checks=['M 25-04B','Microbiology','Pre-hospital medical care','Immunology','05 Oct to 12 Dec','Physiology-1'] print('pages',len(r.pages),'size',r.pages[0].mediabox.width,r.pages[0].mediabox.height) for c in checks: print(c, c in text) assert len(r.pages)==1 and all(c in text for c in checks) PY
M 25 04B Schedule 2026 2027
PDF Document · PDF