• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    해결됨

모듈화 과정에서 pylint 오류가 잔뜩나면서.. 직접 임포트를 하더라도 해결이 안되던데 왜그럴까요?

22.04.10 19:45 작성 조회수 311

2

안녕하세요 남박사님..!
 
계속 질문 해서 죄송합니다..ㅠ
 
이번은 모듈화 과정에서 계속 문제가 나서 어떻게 해야할까 해서 질문을 올립니다..!
코드가 아예 먹통이 되는거 같더라구요..!
 
직접 임포트해서 넣은 common,py / filter.py 는 pylint 내용은 나오더라도 오류는 안나는데.. 다른거는 직접 넣어도 전부 오류가 나오네요..!
 
다른분들이 올리신 글보고 vscode settings에서 format on save 체크가 되어 있어서 해제 했습니다!
 
이 부분도 이렇게 추가해서 해봤는데 같았습니다!
 
from main import member
from main import board
from main.filter import format_datetime
from main.common import login_required
 
 
board.py 코드 부분에서 edit 에 is data in None: <<< None이 빨간줄로 표시가 나오던데 왜그런걸까요?
 
@app.route("/edit/<idx>", methods=["GET", "POST"])
def board_edit(idx):
    if request.method == "GET":
        board = mongo.db.board
        data = board.find_one({"_id": ObjectId(idx)})
        if data in None:
            flash("해당 게시물이 존재하지 않습니다.")
            return redirect(url_for("lists"))
        else:
            if session.get("id") == data.get("writer_id"):
                return render_template("edit.html", data=data)
            else:
                flash("글 수정 권한이 없습니다.")
                return redirect(url_for("lists"))
    else:
        title = request.form.get("title")
        contains = request.form.get("contents")

        board = mongo.db.board
        data = board.find_one({"_id": ObjectId(idx)})
        if session.get("id") == data.get("writer_id"):
            board.update_one({"_id": ObjectId(idx)}, {
                "$set": {
                    "title": title,
                    "contents": contains,
                }
            })
            flash("수정 되었습니다.")
            return redirect(url_for("board_view", idx=idx))
        else:
            flash("글 수정 권한이 없습니다.")
            return redirect(url_for("lists")
 
 
- 터미널 오류-
 
 
 
 
-pylint 추가오류-
 
 
 
 
- 코드오류 -1 -
기존 임포트 처럼 전부 넣어도 오류가 나오네요.. flaek8 로 변경해도 똑같습니다..!
 
 
 
 
- 코드오류 -2 -
 
 
 
- 코드 오류-3-
 
 
 
 
-코드 내용-
 
- run.py-
from main import app

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True, port=9000)
 
 
 
 
 
 
 
 
 
---------------------------------------------------------------------------------------
 
 
- __init__.py -
 
 
from flask import Flask
from flask import request
from flask import render_template
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
from datetime import datetime, timedelta
from flask import abort
from flask import redirect
from flask import url_for
from flask import flash
from flask import session
import math
import time

from . import member
from . import board
from .filter import format_datetime
from .common import login_required

app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb"
app.config["SECRET_KEY"] = "abcd"
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=30)
mongo = PyMongo(app)
 
 
 
 
 
--------------------------------------------------------------------------------------
 
 
-board.py-
 
 
from main import *

from flask import Flask
from flask import request
from flask import render_template
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
from datetime import datetime, timedelta
from flask import abort
from flask import redirect
from flask import url_for
from flask import flash
from flask import session
import math
import time


@app.route("/list")
def lists():
    # 페이지 값 (값이 없는 경우 기본값는 1)
    page = request.args.get("page", 1, type=int)
    # 한페이지당 몇개의 게시물을 출력할지
    limit = request.args.get("limit", 5, type=int)

    search = request.args.get("search", -1, type=int)
    keyword = request.args.get("keyword", "", type=str)

    # 최종적으로 완성된 쿼리를 만들 변수
    query = {}
    # 검색어 상태를 추가할 리스트 변수
    search_list = []

    if search == 0:
        search_list.append({"title": {"$regex": keyword}})
    elif search == 1:
        search_list.append({"contents": {"$regex": keyword}})
    elif search == 2:
        search_list.append({"title": {"$regex": keyword}})
        search_list.append({"contents": {"$regex": keyword}})
    elif search == 3:
        search_list.append({"name": {"$regex": keyword}})

    # 검색 대상이 한개라도 존재할 경우 query 변수에 $or 리스트를 쿼리 합니다.
    if len(search_list) > 0:
        query = {"$or": search_list}

    print(query)

    board = mongo.db.board
    datas = board.find({}).skip(
        (page - 1) * limit).limit(limit).sort("pubdate", -1)

    # 게시물의 총 갯수
    tot_count = board.count_documents({})
    # 마지막 페이지의 수를 구한다.
    last_page_num = math.ceil(tot_count / limit)
    # 페이지 블럭을 5개씩 표기
    block_size = 5
    # 현재 블럭의 위치
    block_num = int((page - 1) / block_size)
    # 블럭의 시작 위치
    block_start = int((block_size * block_num) + 1)
    # 블럭의 끝 위치
    block_last = math.ceil(block_start + (block_size - 1))

    return render_template("list.html", datas=list(datas), limit=limit, page=page, block_start=block_start, block_last=block_last, last_page_num=last_page_num, search=search, keyword=keyword)


@app.route("/view/<idx>")
@login_required
def board_view(idx):
    # idx = request.args.get("idx")
    if idx is not None:
        page = request.args.get("page")
        search = request.args.get("search")
        keyword = request.args.get("keyword")

        board = mongo.db.board
        # data = board.find_one({"_id": ObjectId(idx)})
        data = board.find_one_and_update({"_id": ObjectId(idx)}, {
            "$inc": {"view": 1}}, return_document=True)

        if data is not None:
            result = {
                "id": data.get("_id"),
                "name": data.get("name"),
                "title": data.get("title"),
                "contents": data.get("contents"),
                "pubdate": data.get("pubdate"),
                "view": data.get("view"),
                "writer_id": data.get("writer_id", "")
            }

            return render_template("view.html", result=result, page=page, search=search, keyword=keyword)
    return abort(404)


@app.route("/write", methods=["GET", "POST"])
def board_write():
    if session.get("id") is None:
        return redirect(url_for("member_login"))

    if request.method == "POST":
        name = request.form.get("name")
        title = request.form.get("title")
        contents = request.form.get("contents")
        print(name, title, contents)

        current_utc_time = round(datetime.utcnow().timestamp() * 1000)
        board = mongo.db.board
        post = {
            "name": name,
            "title": title,
            "contents": contents,
            "pubdate": current_utc_time,
            "writer_id": session.get("id"),
            "view": 0,
        }

        x = board.insert_one(post)
        print(x.inserted_id)
        return redirect(url_for("board_view", idx=x.inserted_id))
    else:
        return render_template("write.html")


@app.route("/edit/<idx>", methods=["GET", "POST"])
def board_edit(idx):
    if request.method == "GET":
        board = mongo.db.board
        data = board.find_one({"_id": ObjectId(idx)})
        if data in None:
            flash("해당 게시물이 존재하지 않습니다.")
            return redirect(url_for("lists"))
        else:
            if session.get("id") == data.get("writer_id"):
                return render_template("edit.html", data=data)
            else:
                flash("글 수정 권한이 없습니다.")
                return redirect(url_for("lists"))
    else:
        title = request.form.get("title")
        contains = request.form.get("contents")

        board = mongo.db.board
        data = board.find_one({"_id": ObjectId(idx)})
        if session.get("id") == data.get("writer_id"):
            board.update_one({"_id": ObjectId(idx)}, {
                "$set": {
                    "title": title,
                    "contents": contains,
                }
            })
            flash("수정 되었습니다.")
            return redirect(url_for("board_view", idx=idx))
        else:
            flash("글 수정 권한이 없습니다.")
            return redirect(url_for("lists"))


@app.route("/delete/<idx>")
def board_delete(idx):
    board = mongo.db.board
    data = board.find_one({"_id": ObjectId(idx)})
    if data.get("writer_id") == session.get("id"):
        board.delete_one({"_id": ObjectId(idx)})
        flash("삭제 되었습니다.")
    else:
        flash("삭제 권한이 없습니다.")
    return redirect(url_for("lists"))
 
 
-------------------------------------------------------------------------------------------------------
 
 
- member.py -
 
 
 
from main import *


@app.route("/join", methods=["GET", "POST"])
def member_join():
    if request.method == "POST":
        name = request.form.get("name", type=str)
        email = request.form.get("email", type=str)
        pass1 = request.form.get("pass", type=str)
        pass2 = request.form.get("pass2", type=str)

        if name == "" or email == "" or pass1 == "" or pass2 == "":
            flash("입력되지 않은 값이 있습니다.")
            return render_template("join.html")
        if pass1 != pass2:
            flash("비밀번호가 일치하지 않습니다.")
            return render_template("join.html")

        members = mongo.db.members
        cnt = members.count_documents({"email": email})

        if cnt > 0:
            flash("중복된 이메일 주소입니다.")
            return render_template("join.html")

        current_utc_time = round(datetime.utcnow().timestamp() * 1000)

        post = {
            "name": name,
            "email": email,
            "pass": pass1,
            "joindate": current_utc_time,
            "logintime": "",
            "logincount": 0,
        }

        members.insert_one(post)

        return redirect(url_for("member_login"))
    else:
        return render_template("join.html")


@app.route("/login", methods=["GET", "POST"])
def member_login():

    if request.method == "POST":
        email = request.form.get("email")
        password = request.form.get("pass")
        next_url = request.form.get("next_url")
        members = mongo.db.members
        data = members.find_one({"email": email})

        if data is None:
            flash("회원 정보가 없습니다.")
            return redirect(url_for("member_login"))
        else:
            if data.get("pass") == password:
                session["email"] = email
                session["name"] = data.get("name")
                session["id"] = str(data.get("_id"))
                session.permanent = True
                if next_url is not None:
                    return redirect(next_url)
                else:
                    return redirect(url_for("lists"))
                return redirect(url_for("lists"))
            else:
                flash("비밀번호가 일치하지 않습니다.")
                return redirect(url_for("member_login"))
        return ""
    else:

        next_url = request.args.get("next_url", type=str)
        if next_url is not None:
            return render_template("login.html", next_url=next_url)
        else:
            return render_template("login.html")
 
 
 
--------------------------------------------------------------------------------------------------
 
 
 
- common.py-
 
 
from functools import wraps
from main import session, redirect, request, url_for


def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if session.get("id") is None or session.get("id") == "":
            return redirect(url_for("member_login", next_url=request.url))
        return f(*args, **kwargs)
    return decorated_function
 
 
 
-------------------------------------------------------------------------------------------------------
 
 
 
- fliter.py -
 
 
 
from main import app, datetime, time


@app.template_filter('formatdatetime')
def format_datetime(value):
    if value is None:
        return ""

    now_timestamp = time.time()
    offset = datetime.fromtimestamp(
        now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
    value = datetime.fromtimestamp((int(value) / 1000)) + offset
    return value.strftime('%Y-%m-%d %H:%M:%S')
 
 
 
 
 
 
 
 
 
 
 
 

답변 1

답변을 작성해보세요.

0

강좌를 어디까지 진행하셨는지 정확히 알 수 없지만, 일단 pylint 는 무시하셔야 할듯 합니다. lint 는 코딩에 도움을 주는 역할일 뿐이지 그 자체가 중요한 요소는 아닙니다.

그리고 __init__.py 에서 app 가 .common, .filter 뒤에 나오면 당연히 .common 이나 .filter 에서는 main 을 접근할 수 없습니다. import 순서도 중요합니다.

A 에 app 를 선언했는데 A 에 app 이전에 B 를 import 하면 B 에서는 자신이 import 된 이후에 app 가 선언되었으므로 당연이 A.app 를 인식할 수 없게 됩니다.

그리고 board 에는 from main import * 이것만 있으면 됩니다.

from flask import Flask
from flask import request
from flask import render_template
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
from datetime import datetime, timedelta
from flask import abort
from flask import redirect
from flask import url_for
from flask import flash
from flask import session
import math
import time

app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb"
app.config["SECRET_KEY"] = "abcd"
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=30)
mongo = PyMongo(app)

# 아래의 파일들에서 main 의 app 에 접근을 해야하니
# 아래 import 위에 app 가 선언되어야 합니다.
from .filter import format_datetime
from .common import login_required

# member, board 에서 login_required, format_datetime 을 사용하니까 
# 당연히 member 와 board 가 위의 import 보다 먼저 나와선 안됩니다.
from . import member  
from . import board
문신호님의 프로필

문신호

질문자

2022.04.11

답변주신 내용확인해서 수정해서 적용해봤는데 오류가 나는부분은 사라지지 않아서 해결이 어렵네요..ㅠ

강좌진행중인 부분은 플라스크 프로젝트를 모듈화 하여 패키징 하기 부분입니다.

 

궁금사항은 이렇습니다..!

1. pylint 오류를 해결하는 방안은 있을까요?

2. 오류를 해결 안하고 진행하면 blueprint를 사용해서 라우팅하기가 진행이 될까요?

3. pylint 말고 다른 방법으로 모듈화 하는 방법은 있나요?

4. pylint는 그냥 1개로 사용하고 나머지 HTML부분만 모듈화가 가능할까요?

 

따라 하지않고 강좌시청은 부트스트랩까지 진행했습니다. 

 

플라스크내 모듈화 한다음에는 run.py를 실행하면 오류가 이렇게 나와서 로컬서버가 열리지가 않네요..ㅠ

 

Traceback (most recent call last):

  File "c:\Users\sosgx\Desktop\myweb_01\run.py", line 1, in <module>

    from main import app

  File "c:\Users\sosgx\Desktop\myweb_01\main\__init__.py", line 1, in <module>

    from flask import Flask

ModuleNotFoundError: No module named 'flask'

 

모듈화를 안하고 진행해도 괜찮을까요?

1. pylint 오류를 해결하는 방안은 있을까요?

pylint 는 문법과 코딩 스타일을 체크만 해주는 프로그램이지 오류를 체크하는 프로그램은 아닙니다. 문법적 코딩 스타일에 대한 경고만 주지 실제 프로그램의 동작에는 영향을 주지 않습니다.

 

2. 오류를 해결 안하고 진행하면 blueprint를 사용해서 라우팅하기가 진행이 될까요?

강좌의 흐름은 순차적이기 때문에 해당 오류를 수정하지 않으면 뒤로갈수록 점점 더 복잡해지기만할 문제가 있을듯 합니다.

 

3. pylint 말고 다른 방법으로 모듈화 하는 방법은 있나요?

모듈화랑 pylint 는 아무런 관련이 없습니다. 다시 말씀드리지만 pylint 는 코딩 스타일을 도와주는 그냥 안내역할만 합니다.

 

4. pylint는 그냥 1개로 사용하고 나머지 HTML부분만 모듈화가 가능할까요?

pylint 를 1개로 한다는게 무슨 말씀이신지 모르겠습니다.

 

 

Traceback (most recent call last):

  File "c:\Users\sosgx\Desktop\myweb_01\run.py", line 1, in <module>

    from main import app

  File "c:\Users\sosgx\Desktop\myweb_01\main\__init__.py", line 1, in <module>

    from flask import Flask

ModuleNotFoundError: No module named 'flask'

 

 올려주신 오류를 보면 갑자기 flask 자체를 찾지 못하는건 무슨 이유인가요? virtualenv 를 사용중이신건가요? 아니신건가요?

from flask import Flask는 모듈화가 되었던 안되었던 오류가 나서는 안되는 내용인듯 보입니다만....

 

https://open.kakao.com/o/svwMTm1d

 

시간되실때 카톡으로 문의한번 주셔보세요

문신호님의 프로필

문신호

질문자

2022.04.12

4번은 pylint를 활용해서 py파일을 전부 모듈화로 변경했잖아요? html파일도 모듈화 하는 부분이 있어서요! run.py를 모듈화 하지 않고 html만 모듈화 해도 괜찮은지 물어본거였습니다!

 

다른부분은 해결되서 수업 진행하는데는 문제가 없습니다! 설명해주셔서 감사합니다!

 

 

위에 오류는 이렇습니다.

cmd에서 환경은 virtualenv 사용중인 (venv) C:\Users\sosgx\Desktop\myweb_01> 입니다.

여기서 python run.py을 하면 아래와 같은 오류가 나오더라구요.

 

(venv) C:\Users\sosgx\Desktop\myweb_01>python run.py 

Traceback (most recent call last):

  File "run.py", line 1, in <module>

    from main import app

  File "C:\Users\sosgx\Desktop\myweb_01\main\__init__.py", line 1, in <module>

    from flask import Flask

 

ModuleNotFoundError: No module named 'flask'

 

라고 나오고 상당에 재생버튼 누르면 code넘어가면서 이렇게 나옵니다.

 

S C:\Users\sosgx\Desktop\myweb_01> python -u "c:\Users\sosgx\Desktop\myweb_01\run.py"

Traceback (most recent call last):

  File "c:\Users\sosgx\Desktop\myweb_01\run.py", line 1, in <module>

    from main import app

  File "c:\Users\sosgx\Desktop\myweb_01\main\__init__.py", line 1, in <module>

    from flask import Flask

ModuleNotFoundError: No module named 'flask'

PS C:\Users\sosgx\Desktop\myweb_01> & c:/Users/sosgx/Desktop/myweb_01/venv/Scripts/Activate.ps1

 

(venv) PS C:\Users\sosgx\Desktop\myweb_01>

 

여기서 다시 재생버튼 누르면 아래처럼 실행되면서 로컬서버가 동작합니다. 

 

  File "c:\Users\sosgx\Desktop\myweb_01\tempCodeRunnerFile.py", line 1, in <module>

    from main import app

  File "c:\Users\sosgx\Desktop\myweb_01\main\__init__.py", line 1, in <module>

    from flask import Flask

ModuleNotFoundError: No module named 'flask'

PS C:\Users\sosgx\Desktop\myweb_01> & c:/Users/sosgx/Desktop/myweb_01/venv/Scripts/Activate.ps1

(venv) PS C:\Users\sosgx\Desktop\myweb_01> python -u "c:\Users\sosgx\Desktop\myweb_01\tempCodeRunnerFile.py"

 * Serving Flask app 'main' (lazy loading)

 * Environment: production

   WARNING: This is a development server. Do not use it in a production deployment.

   Use a production WSGI server instead.

 * Debug mode: on

 * Restarting with stat

 * Debugger is active!

 * Debugger PIN: 133-167-640

 * Running on all addresses.

   WARNING: This is a development server. Do not use it in a production deployment.

 * Running on http://192.168.0.34:9000/ (Press CTRL+C to quit)

 

이렇게 나오는 부분은 왜그런걸까요..?

"4번은 pylint를 활용해서 py파일을 전부 모듈화로 변경했잖아요? html파일도 모듈화 하는 부분이 있어서요! run.py를 모듈화 하지 않고 html만 모듈화 해도 괜찮은지 물어본거였습니다!"

다시 말씀드리지만 pylint 를 활용해서 모듈화한게 아닙니다. 모듈화랑 pylint 는 아무런 관련이 없습니다. pylint 는 그냥 코딩 도우미일뿐 안써도 코딩하는데 아무런 상관없는 겁니다.

그리고 모듈화는 개발자가 프로그램을 좀 더 구조화하여 객체지향적으로 코딩하는 방법의 하나일뿐 필수 요소는 아니나 강좌의 커리큘럼상 뒷 부분에 모듈화되어 진행하게 되는 부분이라 강좌의 진도를 따라가시려면 해야한다고 답변 드린 것 입니다.

그리고 추가로 질문하신 부분은 현재 프로젝트가 virtualenv 환경에서 라이브러리가 설치되어있고 현재 프로젝트 폴더에 venv 폴더가 존재하므로 비주얼스튜디오 코드가 해당 폴더를 자동 인식하여 인터프리터를 가상환경으로 설정했기 때문입니다. 가상환경 virtualenv 에 대해 꼭 이해하고 넘어가시기 바랍니다.

문신호님의 프로필

문신호

질문자

2022.04.12

답변 감사드립니다.

지금 진도는 나가고 있고 아직은 오류가 없어서 질문이 생기면 다시 말씀드리겠습니다~! 

한번 완강하고 다시 복습을 해봐야겠네요 ㅎㅎ