diddi- / flask-seeder

Flask extension for seeding database
32 stars 11 forks source link

Error during running flask seed #8

Closed lterelak closed 4 years ago

lterelak commented 4 years ago

When i run flask seed i get this error: AttributeError: module 'flask_seeder.seeder' has no attribute 'path'

Whole error is here.

Running database seeders Traceback (most recent call last): File "c:\users\luiza\appdata\local\programs\python\python37\lib\importlib\util.py", line 96, in find_spec parent_path = parent.path AttributeError: module 'flask_seeder.seeder' has no attribute 'path'

The above exception was the direct cause of the following exception:

Traceback (most recent call last): File "c:\users\luiza\appdata\local\programs\python\python37\lib\pkgutil.py", line 493, in find_loader spec = importlib.util.find_spec(fullname) File "c:\users\luiza\appdata\local\programs\python\python37\lib\importlib\util.py", line 100, in find_spec f"while trying to find {fullname!r}", name=fullname) from e ModuleNotFoundError: path attribute not found on 'flask_seeder.seeder' while trying to find 'flask_seeder.seeder.ext'

The above exception was the direct cause of the following exception:

Traceback (most recent call last): File "c:\users\luiza\appdata\local\programs\python\python37\lib\runpy.py", line 193, in _run_module_as_main "main", mod_spec) File "c:\users\luiza\appdata\local\programs\python\python37\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Users\Luiza\AppData\Local\Programs\Python\Python37\Scripts\flask.exe__main.py", line 9, in File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\cli.py", line 967, in main cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\cli.py", line 586, in main return super(FlaskGroup, self).main(args, kwargs) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 782, in main rv = self.invoke(ctx) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 1066, in invoke return ctx.invoke(self.callback, ctx.params) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 610, in invoke return callback(args, kwargs) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\decorators.py", line 21, in new_func return f(get_current_context(), *args, *kwargs) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\cli.py", line 426, in decorator return __ctx.invoke(f, args, kwargs) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\click\core.py", line 610, in invoke return callback(*args, **kwargs) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask_seeder\cli.py", line 162, in seed_run for seeder in get_seeders(root=root): File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask_seeder\cli.py", line 122, in get_seeders seeders.extend(get_seeders_from_script(script)) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask_seeder\cli.py", line 97, in get_seeders_from_script spec.loader.exec_module(module) File "", line 728, in exec_module File "", line 219, in _call_with_frames_removed File "seeds\seeds.py", line 6, in app = Flask(name) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 416, in init__ self, import_name, template_folder=template_folder, root_path=root_path File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\helpers.py", line 980, in init root_path = get_root_path(self.import_name) File "c:\users\luiza\appdata\local\programs\python\python37\lib\site-packages\flask\helpers.py", line 786, in get_root_path loader = pkgutil.get_loader(import_name) File "c:\users\luiza\appdata\local\programs\python\python37\lib\pkgutil.py", line 479, in get_loader return find_loader(fullname) File "c:\users\luiza\appdata\local\programs\python\python37\lib\pkgutil.py", line 499, in find_loader raise ImportError(msg.format(fullname, type(ex), ex)) from ex ImportError: Error while finding loader for 'flask_seeder.seeder.ext' (<class 'ModuleNotFoundError'>: path attribute not found on 'flask_seeder.seeder' while trying to find 'flask_seede r.seeder.ext')

I do not know what can be wrong.

diddi- commented 4 years ago

I'm not sure what could be wrong just from the errors, could you add some example code to reproduce this?

lterelak commented 4 years ago

Hi, I am newbginner with python and flask. VirtualAssistants.py in my code is the same what app.py in your example. I put some code which I think is relevant to check. I have of course more code, the app works properly with other functions.

My structure looks like

seeds --- init.py --- demo.py VirtualAssistants.py

init.py is empty

demo.py


from flask_seeder import Seeder, Faker
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)

class VirtualAssistant(db.Model):
  def __init__(self, id=None, name=None, last_name=None, job=None, image_filename=None, image_url=None):
    self.id = db.Column(db.Integer, primary_key=True)
    self.name = db.Column(db.String(30), name)
    self.last_name = db.Column(db.String(30), last_name)
    self.job = db.Column(db.String(30), job)
    self.image_filename = db.Column(db.String, image_filename)
    self.image_url = db.Column(db.String, image_url)

  def __str__(self):
    return "id=%d, name=%s, last_name=%s, job=%s, image_filename=%s, image_url=%s, " % (self.id, self.name, self.last_name, self.job, self.image_filename, self.image_url)

class DemoSeeder(Seeder):

  def run(self):
    faker = Faker(
      cls=VirtualAssistant,
      init={
        "id": 1,
        "name": "Marek",
        "last_name": "Krol",
        "job": "teacher",
        "image_filename": "example.jpg",
        "image_url": "thispersondoesnotexist.com"
      }
    )

    # Create 1 virtul assistant
    for VirtualAssistant in faker.create(5):
      print("Adding VirtualAssistant: %s" % VirtualAssistant)
      self.db.session.add(VirtualAssistant)

VirtualAssistants.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_seeder import FlaskSeeder
app = Flask(__name__)
db = SQLAlchemy(app)
db.init_app(app)
seeder = FlaskSeeder()
seeder.init_app(app, db)

class VirtualAssistant(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    last_name = db.Column(db.String(30))
    job = db.Column(db.String(30))
    image_filename = db.Column(db.String)
    image_url = db.Column(db.String)

    def __repr__(self, name, last_name, job, image_filename, image_url):
        self.name = name
        self.last_name = last_name
        self.job = job
        self.image_filename
        self.image_url

if __name__ == "__main__":
    app.run(debug=True)
diddi- commented 4 years ago

Thanks for sharing the code, I was able to reproduce the error you see. I believe there's a bit of a confusion on how to setup Flask and SQLAlchemy, which is totally understandable as there is of course more than one way to do it.

Since VirtualAssistants.py is your app it will be loaded first and this is where you set up the app and db objects. Once that is done you can import db from your seeds/demo.py module.

I also noticed in your DemoSeeder class you're using VirtualAssistant both as input to Fake but also as a variable when printing the output, This will cause errors like local variable 'VirtualAssistant' referenced before assignment.

With that in mind, I've modified your code and below is my take on it. Please use and modify further as you see fit. Hopefully this could work as a base

VirtualAssistants.py

from flask import Flask
from flask_seeder import FlaskSeeder
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
db = SQLAlchemy(app)
seeder = FlaskSeeder()
seeder.init_app(app, db)

seeds/demo.py

from flask_seeder import Seeder, Faker
from VirtualAssistants import db

class VirtualAssistant(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    last_name = db.Column(db.String(30))
    job = db.Column(db.String(30))
    image_filename = db.Column(db.String)
    image_url = db.Column(db.String)

    def __init__(self, id=None, name=None, last_name=None, job=None, image_filename=None, image_url=None):
        self.id = id
        self.name = name
        self.last_name = last_name
        self.job = job
        self.image_filename = image_filename
        self.image_url = image_url

    def __str__(self):
        return "id=%d, name=%s, last_name=%s, job=%s, image_filename=%s, image_url=%s, " % (self.id, self.name, self.last_name, self.job, self.image_filename, self.image_url)

class DemoSeeder(Seeder):

    def run(self):
        faker = Faker(
            cls=VirtualAssistant,
            init={
                "id": 1,
                "name": "Marek",
                "last_name": "Krol",
                "job": "teacher",
                "image_filename": "example.jpg",
                "image_url": "thispersondoesnotexist.com"
            }
        )

        # Create 1 virtul assistant
        for assistant in faker.create(5):
          print("Adding VirtualAssistant: %s" % assistant)
          self.db.session.add(assistant)
lterelak commented 4 years ago

Thank you so much! It works now. I got another error which I have fixed.

Error was:

sqlalchemy.exc.InvalidRequestError: Table 'virtual_assistant' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing T able object.

According to Stack Overflow https://stackoverflow.com/questions/37908767/table-roles-users-is-already-defined-for-this-metadata-instance I have modifed model in demo.py to

class VirtualAssistant(db.Model):
    __table_args__ = {'extend_existing': True}
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    last_name = db.Column(db.String(30))
    job = db.Column(db.String(30))
    image_filename = db.Column(db.String)
    image_url = db.Column(db.String)

and now everything works properly. :)

lterelak commented 4 years ago

Hi,

I have only one more question. Do you know what I can do to generate fake job, image_filename, last_name, image_url in way that I can create 5 different assistants by running one command?

Now I have to make it manually, so it will be one by one, not all 5 together and I have to find out all names by myself. I am wondering if maybe you could give me some tips what I can read to achieve this? Or maybe this is impossible and the only way is to make it manually?

diddi- commented 4 years ago

This is where the generators come in, and specifically generator.String. For example you could create random jobs and images using String patterns (see README for details)

from flask_seeder import generator
....
  "job": generator.String("(teacher|pilot|developer)"), # One of "teacher", "pilot" or "developer"
  "image_filename": generator.String("[0-9]{1,2}.jpg"), # Random one or two digit filename

Basically this will randomize the job and image_filename values for each iteration of faker.create. You can also create your own generators if you need more control of the generation process.

Hope that helps!

lterelak commented 4 years ago

Thanks so much Diddi! :) Have a nic day.