Python Forum
Why variable is available in function without declaring ?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why variable is available in function without declaring ?
#1
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import re
from datetime import datetime
from datetime import timedelta
import logging
from logging.handlers import RotatingFileHandler
from os import path
from time import sleep


def get_settings(file):
    settings = {}

    try:
        with open(file) as f:

            for line in f:
                try:
                    arr = line.split(":")
                    arr = [line.strip() for line in arr]
                    settings[arr[0]] = arr[1]
                except IndexError:
                    continue

    except FileNotFoundError as e:
        print(e)
        exit(1)

    return settings


def find_string(expr):
    pattern = re.compile(r"{}".format(expr))
    string = soup.find(text=pattern).__dict__
    return string


def get_date(string):
    match = re.findall(r"\d{4}-\d{2}-\d{2}", string)
    return match


def get_ok(string):
    pattern = re.compile("glyphicon-ok")
    match = re.search(pattern, str(string))

    if not match:
        return False
    else:
        return True


def unsent_checks():
    string = find_string("Неотправленные чеки")["next_element"].getText()
    res = get_date(string)

    try:
        date = datetime.strptime(res[0], '%Y-%m-%d').date()
    except (AttributeError, IndexError):
        date = None

    if date:
        return string
    else:
        return None


def ok_check(string):
    string = find_string(string)
    res = get_ok(string["previous_element"])

    if not res:
        logger.error(string["next_element"].getText())


def check_date(string, days):
    string = find_string(string)["next_element"].getText()
    date = get_date(string)[1]
    date = datetime.strptime(date, '%Y-%m-%d').date() - timedelta(days)

    if datetime.now().date() > date:
        logger.warning(string)


settings_vars = get_settings("{}/settings.yaml".format(path.dirname(path.abspath(__file__))))
log_format = "%(asctime)s - %(levelname)s: %(message)s"

logger = logging.getLogger("log")
logger.setLevel("INFO")
handler = RotatingFileHandler("{}/{}".format(path.dirname(path.abspath(__file__)), settings_vars["log_filename"]),
                              maxBytes=1024, backupCount=5)
logger.addHandler(handler)
formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s")
handler.setFormatter(formatter)
logging.getLogger("urllib3").setLevel(logging.WARNING)

try:
    cert_warn_days = int(settings_vars["cert_warn_days"])
except ValueError:
    cert_warn_days = None
    logger.error("check 'cert_warn_days' in settings.yaml")
    exit(1)

text = requests.get("http://{}:{}".format(settings_vars["utm_address"], settings_vars["utm_port"])).text
soup = BeautifulSoup(text, 'html.parser')

unsent_error_counter = 0
while True:
    unsent_string = unsent_checks()

    if unsent_string:
        unsent_error_counter += 1

        if unsent_error_counter > settings_vars["unsent_error_limit"]:
            logger.error(unsent_string)
            unsent_error_counter = 0

    ok_check("Продуктивный контур")
    ok_check("Статус лицензии")
    check_date("Сертификат RSA", cert_warn_days)
    check_date("Сертификат ГОСТ", cert_warn_days)
    logger.info("OK")
    sleep(60)
It was written by me but now I really can't understand why "soup" is available in "def find_string(expr)" Can anybody explain ? By the way may be there is some weakness in my code ?

Now I understand )))
Reply
#2
soup is BeautifulSoop() instance.

It is available in the global space. Python first looks in function's local namespace for the objects and if they are not there it looks in the global namespace.

As time module in your script:

import time

def the_time():
    print(time.asctime())

the_time()
So you create BeautifulSoup object called soup. Which has a bunch of methods. It is not indented so it is in the global namespace and you can access it directly. Just like time.

In [1]: from bs4 import BeautifulSoup

In [2]: import requests

In [3]: html = requests.get('http://python-forum.io/').content

In [4]: BeautifulSoup(html, 'lxml').find('title').text
Out[4]: 'Python Forum'
Here I am not creating any BS object. I can use this or the eventually created 'soup' object in any function definition.

In [5]: soup = BeautifulSoup(html, 'lxml')

In [6]: for obj in dir():
   ...:     if obj == 'soup':
   ...:         print(obj)
   ...:         
soup

In [7]: def get_title():
   ...:     title = BeautifulSoup(html, 'lxml').find('title').text
   ...:     print(title)
   ...:     title = soup.find('title').text
   ...:     print('soup object', title)
   ...:     

In [8]: get_title()
Python Forum
soup object Python Forum
You can also pass it as an argument for sure.
In [9]: def get_title(inner_soup):
    ...:     title = BeautifulSoup(html, 'lxml').find('title').text
    ...:     print(title)
    ...:     title = inner_soup.find('title').text
    ...:     print('inner_soup object', title)
    ...:     

In [10]: get_title(soup)
Python Forum
inner_soup object Python Forum
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#3
Thanks. Spasibo)))
Reply
#4
Dla nichevo
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020