0
\$\begingroup\$

I'm making a weather simulator with Python's Ursina engine, but I cannot load models.

The error stack:

C:\Users\x\Desktop\WeatherSim>WeatherSim.py
...
Loading assets: Assets/Models/Plane.obj
Traceback (most recent call last):
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 207, in <module>
    Assets.LoadM("Empty","Assets/Models/Plane.obj")
  File "C:\Users\x\Desktop\WeatherSim\WeatherSim.py", line 163, in LoadM
    setattr(self,n,load_model(obj_to_ursinamesh(obj)))
                              ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\site-packages\ursina\mesh_importer.py", line 224, in obj_to_ursinamesh
    for f in path.glob(f'**/{name}.obj'):
             ^^^^^^^^^
AttributeError: 'str' object has no attribute 'glob'

C:\Users\x\Desktop\WeatherSim>

Some code (imports, the Assets.LoadM() function and the function call):

from contextlib import contextmanager

...

@contextmanager
def no_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:  
            yield
        finally:
            sys.stdout = old_stdout

...

with no_stdout():
    from ursina import *
    from ursina.mesh_importer import *
    app = Ursina()

...

class _assets:
    ...
    # load a model and assigns it to the new attribute with name n to _assets
    def LoadM(self,n,obj):
        setattr(self,n,load_model(obj_to_ursinamesh(obj)))

Assets = _assets()

...

# the \r and end="" is so that it prints every "Load assets: ..." line in one line
print("\rLoading assets: Assets/Models/Plane.obj",end="")
Assets.LoadM("MeshPlane","Assets/Models/Plane.obj")

Also, I don't want to use Ursina's built-in plane mesh since mine has special UV coordinates, sizes, etc.

What is the cause of this error?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

You get this error because you don't pass the right thing to obj_to_ursinamesh.

I'm not sure whether you're using the engine the way it is meant to be used, so you need to be very much aware how to debug your code and find your way around when doing something exotic with a library.

In this specific case, you call obj_to_ursinamesh with a string. Looking at the function in the source of the engine, we find (formatted):

def obj_to_ursinamesh(path=application.compressed_models_folder, 
        outpath=application.compressed_models_folder, name='*', return_mesh=True, 
        save_to_file=False, delete_obj=False):
    if name.endswith('.obj'):
        name = name[:-4]

    for f in path.glob(f'**/{name}.obj'):
        # filepath = path / (os.path.splitext(f)[0] + '.obj')
        print('read obj at:', f)

[...]

Looking around, the path object that you pass as the first and single parameter is expected to be a Path from pathlib, not a string (it appears to be the type of application.compressed_models_folder).

Now looking at how the function is written, you need to pass the directory path as a separate argument from the actual model you want to load, unless you want to load all the models in that directory.

You'll likely need to call obj_to_ursinamesh like such:

obj_to_ursinamesh(path=Path('Assets/Models'), name='Plane')

or

obj_to_ursinamesh(path=Path('Assets/Models'), name='Plane.obj')

So the key takeaways here: dig, dig, dig deeper in the source engine to see how it works, how are the parameters composed, what is the chain of functions that are called.

\$\endgroup\$
1
0
\$\begingroup\$

This tells you that you've passed a value of type str (a string of text) where code down the line was expecting a type that has a method called .glob. Specifically, the variable that got this unexpected value was called "path".

Doing a quick web search with some key words from the call site, we can find that the Python library PathLib has a Path type that fits this description.

So somewhere you've passed a raw string where a function was expecting a Path object from this library.

Let's look at the Ursina docs to see what they say about how to use the obj_to_ursinamesh function. Note that they wrap their file path in a Path() constructor:

application.asset_folder = Path(r'''C:\Users\Petter\Downloads''')

So, make sure you wrap your asset path string into a Path object before passing it into a function from Ursina that expects paths.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .