So, I can’t load my json file and I don’t know why, can anyone explain what I’m doing wrong?
async def give(msg, arg):
if arg[0] == prefix + "dailycase":
with open("commands/databases/cases.json", "r") as d:
data = json.load(d)
For some reason I’m getting this error:
with open("commands/databases/cases.json", "r") as d:
AttributeError: __enter__
asked Nov 30, 2018 at 20:52
6
I got this error at this line:
with concurrent.futures.ProcessPoolExecutor as executor:
missing brackets was the issue
with concurrent.futures.ProcessPoolExecutor() as executor:
answered Sep 25, 2020 at 9:11
a20a20
5,4452 gold badges29 silver badges27 bronze badges
Most likely, you have reassigned the Python builtin open
function to something else in your code (there’s almost no other plausible way this exception could be explained).
The with
statement will then attempt to use it as a context manager, and will try to call its __enter__
method when first entering the with
block. This then leads to the error message you’re seeing because your object called open
, whatever it is, doesn’t have an __enter__
method.
Look for places in your Python module where you are re-assigning open
. The most obvious ones are:
- A function in the global scope, like
def open(..)
- Direct reassignment using
open =
- Imports like
from foo import open
orimport something as open
The function is the most likely suspect, because it seems your open
is actually a callable.
To aid you finding what object open
was accidentally bound to, you can also try to
print('open is assigned to %r' % open)
immediately before your with
statement. If it doesn’t say <built-in function open>
, you’ve found your culprit.
answered Nov 30, 2018 at 21:06
Lukas GrafLukas Graf
29.8k8 gold badges76 silver badges92 bronze badges
6
In my case, I was intentionally defining a custom with function called stopwatch
with stopwatch('upload %d bytes' % len(data)):
...code...
And so had to add:
import contextlib
and prefix the custom function definition as follows:
@contextlib.contextmanager
def stopwatch(message):
...code...
answered Nov 29, 2020 at 8:23
My problem was that I was expecting os.open
to work like the built-in open
…
This results in AttributeError: __enter__
import os
with os.open('out.txt', os.CREAT) as f:
f.write('hello world')
This does not
with open('out.txt', 'w') as f:
f.write('hello world')
I suppose it would be easy enough to cause the OP problem with from os import open
.
answered Oct 13, 2021 at 17:05
pbateypbatey
1,20713 silver badges13 bronze badges
In this article, we are going to discuss AttributeError: enter. We will understand why this error occurs and what are the possible solutions for that. We will also discuss a brief about python Context Manager to understand the error more clearly.
So what are we waiting for, Let’s get started!
Understanding the AttributeError
So, attributes are the values or function that is associated with any class or a datatype. In simple words, we can say that the properties associated or defined in any class or datatype are called its attribute.
When we try to call or access any attribute on a value that is not associated with its class or data type. We get an attribute error. Let’s try to understand it more clearly. So when we define any variable or instance for any class or datatypes we have access to its attributes. We can use it for our operations but when we try to call an attribute that is not defined for that particular class we get the attribute error. I hope it is clear to you!
Now, before moving to AttributeError: enter, let’s understand the concept of Python Context Manager. It will help us to understand the error clearly and then fix it.
Python Context Manager
So, When we work on any real-time problems, there is the case that we have to handle different files and databases for storing and retrieving data. These files or databases are known as resources. When we try to access these files or databases then there is a supply constraint to them. It means we can access only a limited number of files at once. So it is important to free all those resources on which we are not working. If we somehow failed to free those resources it will cause resource leakage and consequently, slow down the system.
Now, think that when we handle more files and we have to write the same code, again and again, to open and then close the file. Therefore, to solve this problem we try to achieve the DRY ( Don’t Repeat Yourself ) approach.
Here, python Context Manager comes into the picture. It helps us to create different classes to manage those resources. Python uses the “with” keyword to evaluate that whether the class or function is context manager or not.
How to create Context Manager
We can create a context manager by using both class and functions. We will discuss it one by one.
Using Class
class FileManager(): # defining context manager class named FileManager def __init__(self, filename, mode): self.filename = filename self.mode = mode def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_value, traceback): self.file.close() # loading the file Sample.txt to work upon. with FileManager('Sample.txt', 'w') as file: file.write('Sample Testing') print(file.closed)
Output: True
The given snippet of code describes how to create a Context Manager using the python class. Now, let’s try to understand each function in the defined class.
__init__:- This method is used to initialize objects for the given class. once, initialization is complete it invokes the __enter__ function.
__enter__:- The __enter__ function then opens the file in the defined mode and then returns an instance of FileManager class. Then the instance is stored in the “file” variable from this line of code( with FileManager(‘Sample.txt’, ‘w’) as file: ). After this file.write will get executed. Once the writing operation is over, __exit__ function is called automatically.
__exit__:- This function closes the file without mentioning it explicitly every time.
Now, to check whether the file is closed or not we wrote “print(file.closed)” which returns a true value which means that the file is closed.
Now, we will imply the same functionality of context manager using functions.
Using Functions
from contextlib import contextmanager @contextmanager def file_manager(file, mode): # opens the file in given mode and assign it to the variable file. file = open(file,mode) yield file #returns the file variable f.close() # closes the file with open_file('sample.txt') as file: file.write('Sample Testing') print(f.closed) #returns true
Output: True
So in this way, we can also implement context manager using functions. We can also use somewhat the same kind of code for databases too.
Click here to learn more about python Context Manager
Talking about AttributeError: __enter__, we can say that the issue lies within the context manager class. Whenever there is a problem with returning an instance of the class, the given error occurs. Following improper syntax might be one of the reasons for that.
AttributeError: __enter__ in SQLAalchemy
Let’s refer to the following code snippet from StackOverflow to understand this error.
Session = scoped_session(sessionmaker(autoflush=True, autocommit=False, bind=engine)) @contextmanager def session_scope(): session = Session() try: yield session session.commit() except: session.rollback() raise finally: session.close() class SomeClass: def __init__(self): self.session_scope = session_scope def something_with_session(self): with self.session_scope as session: # <-- error . . . . . . . . . . .
Output: AttributeError:__enter__
In the above snippet of code, we are facing the error due to line ” with self.session_scope as session:” which should be as follow:
with self.session_scope() as session:
In this case, we need to understand that we are calling the function to execute and hence we have to write parenthesis after the function.
AttributeError: enter in Tensorflow
def network_run(): with tf.Session as sess: # <-- error sess.run(tf.global_variables_initializer()) for i in range(200): sess.run(opt_D, feed_dict={x_ten: images[np.random.choice(range(len(images)), batch_size)].reshape(batch_size, x_ten_size), z_ten:z_noise(batch_size)}) sess.run(opt_G, feed_dict={z_ten:z_noise(batch_size)}) sess.run(opt_G, feed_dict={z_ten:z_noise(batch_size)}) gen_cost=sess.run(G_img, feed_dict={z_ten:z_noise(batch_size)}) disc_cost=sess.run(D_img, feed_dict={x_ten: images[np.random.choice(range(len(images)), batch_size)].reshape(batch_size, x_ten_size), z_ten:z_noise(batch_size)}) image=sess.run(G(z_ten), feed_dict={z_ten:z_noise(batch_size)}) df=sess.run(tf.sigmoid(D_img_fake), feed_dict={z_ten:z_noise()}) print (i, gen_cost, disc_cost, image.max(), df[0][0]) image=sess.run(G(z_ten), feed_dict={z_ten:z_noise(batch_size)}) image1 = image[0].reshape([28, 28]) im = Image.fromarray(image1) im.show() network_run()
Output:
Traceback (most recent call last):
File "C:Python Practicegan.py", line 93, in <module>
n()
File "C:Python Practicegan.py", line 73, in nn
with tf.Session as sess:
AttributeError: __enter__
In the above snippet of code, we are facing the error due to line ” with tf.Session as sess:” which should be as follow:
with tf.Session() as sess:
Here, we have to take care that we are creating objects for the context manager class from the TensorFlow library. To refer to it as an instance, we have to put parentheses over there.
So it is necessary to follow proper syntax to create and use context manager function and class as explained above.
Conclusion
So, today we discussed, attribute errors, took a brief walkthrough of python Context Manager. We discussed how we can create a context manager class and context manager functions. Then, we also discussed, different functions used in defining the context manager and reason of AttributeError: enter. Then we discuss possible solutions for the given error.
Hope this article helped you. Thank You.
If you want to know more about Attribute Errors in Python Click here.
Trending Python Articles
-
[Fixed] SSL module in Python is Not Available
●May 30, 2023
-
Mastering Python Translate: A Beginner’s Guide
by Namrata Gulati●May 30, 2023
-
Efficiently Organize Your Data with Python Trie
by Namrata Gulati●May 2, 2023
-
[Fixed] modulenotfounderror: no module named ‘_bz2
by Namrata Gulati●May 2, 2023
One error that you might encounter in Python is:
AttributeError: __enter__
This error usually occurs when you use the with
statement to call a context manager.
There are 4 possible causes for this error:
- The
__enter__
attribute is not defined - Using a string in the
with
statement - You replaced the
open()
function - You forget to instantiate the class in the
with
statement
This tutorial explains why this error occurs and how to fix it.
1. The __enter__
attribute is not defined
A context manager is a way to manage resources in Python. It allows you to automatically create and release resources following the execution of your program.
A context manager is called using the with
statement. One of the most familiar examples of using a context manager is when you use Python to open a file and write a string in it:
with open("file.txt", "w") as f_obj:
f_obj.write("first line")
Using the with
statement, a context manager allows you to access the file stream inside the statement’s body.
When you’re done with the file, the with
statement automatically releases the file stream object.
Without the with
statement, you need to close the file stream manually as follows:
f_obj = open("file.txt", "w")
f_obj.write("first line")
# Close the file stream
f_obj.close()
You might be wondering, what’s this got to do with the error?
When you call a context manager using the with
statement, the __enter__
attribute is executed when the context manager creates the resources.
Let’s see an example by defining a class named Car
as follows:
class Car:
def __enter__(self):
print('__enter__: Creating Resources...')
return self
def __exit__(self,exc_type, exc_val, exc_tb):
print('__exit__: Releasing resources...')
The Car
class has both __enter__
and __exit__
attributes. The former is called when you start the context manager, and the latter is called when the context manager is cleared.
Let’s create an object of the Car
class and access the object as follows:
with Car() as obj:
print(obj)
You’ll get the following output:
__enter__: Creating Resources...
<__main__.Car object at 0x10503fac0>
__exit__: Releasing resources...
As you can see, the __enter__
attribute is called when the with
statement is executed.
The error occurs when you use the with
statement with an object that doesn’t have the __enter__
attribute:
class Car:
def __init__(self):
print("Initializing car...")
with Car() as obj:
print(obj)
Output:
Initializing car...
Traceback (most recent call last):
File "main.py", line 6, in <module>
with my_car as obj:
AttributeError: __enter__
To resolve this error, make sure that you have an __enter__
attribute defined in your class.
You also need to add an __exit__
attribute in your class, or you’ll get the AttributeError: __exit__
message.
class Car:
def __init__(self):
print("Initializing car...")
def __enter__(self):
print('__enter__: Creating Resources...')
return self
def __exit__(self,exc_type, exc_val, exc_tb):
print('__exit__: Releasing resources...')
Once you define the attributes, the error should disappear.
2. Using a string in the with
statement
You also get this error when you tried to access a file by directly specifying the file name in the with
statement:
with 'file.txt' as f_obj:
lines=f_obj.readlines()
Output:
Traceback (most recent call last):
File "main.py", line 1, in <module>
with 'file.txt' as file_object:
AttributeError: __enter__
You can’t access a file directly, so use the open()
function instead:
with open("file.txt", "r") as f_obj:
Using the open()
function as shown above should fix the error.
3. You replaced the open()
function
You could also get this error when running the with open()
function:
with open("file.txt", "r") as f_obj:
AttributeError: __enter__
This error occurs when you reassign the open()
function to something else.
You might have created a function that uses the same name like def open()
in your code, or you assign something to it like open = ...
Python will replace the default open()
function with the one you have in your code, so you need to search your code for the cause.
4. You forget to instantiate the class in the with
statement
The with
statement must be used to manage a class instance, which is an object.
If you forget to instantiate the object and use the class instead, you’ll get the same error:
with Car as obj:
print(obj)
# with Car as obj:
# AttributeError: __enter__
The Car
in the above example is written without the parentheses, so the with
statement tries to access the class itself and not the class instance.
You need to create an instance of the class by adding parentheses, e.g. Car()
to fix this error.
Conclusion
This tutorial explains that the AttributeError: __enter__
occurs when the context manager can’t find and execute the __enter__
attribute.
You need to make sure that the __enter__
attribute is defined in your class, and that you’re using the right object in the with
statement.
I hope this tutorial is helpful. See you again in other tutorials! 👋
Table of Contents
- Introduction
- What are attributes in Python?
- How do you write a context manager in Python?
- What is attributeerror __enter__?
- How do you fix attribute errors in Python?
- Summary
- Next Steps
- References
Introduction
If you run into the common Python error message AttributeError: __enter__
, then you likely have been using the with
statement in Python. The with
statement allows you to use context managers, which enable you to automatically set up and release resources.
This Python error attributeerror can be very confusing and lead you to question what’s wrong, but understanding how context managers work will help you to know why the error occurs and prevent it from appearing in the future.
In this article, you’ll learn how to fix and prevent the AttributeError: __enter__ error message by understanding what the attributes, context managers, and common mistakes are that can lead to its occurrence.
What are attributes in Python?
An attribute is used to describe a characteristic of an object, and is of the syntax object.attribute
. In Python, there are two types of attributes: class attributes and instance attributes. Both of these store data related to the class.
A class attribute can store simple variable datatypes like integers and strings, or a more complex datatype like a list (array) or dictionary.
Class attributes are shared across all objects and can also be accessed directly from the class variable. Instance attributes are unique to each instance of a class and are often initialized inside the constructor of the class, also known as the __init__ method.
An easy way to identify instance attributes is that they begin with the prefix «self.» The word self is a placeholder for the instance being supplied.
For example:
>>> class Example:
... classAttr = 1
...
... def __init__(self, instanceAttr):
... self.instanceAttr = instanceAttr
...
... def exampleFunc(self):
... return 3
...
>>>
Here, you have an Example
class. The classAtrr can be accessed either from the instance of the class or the class variable itself. Methods are also considered to be class attributes. So, the method exampleFunc is also a class attribute.
>>> ins = Example(5)
>>> ins.classAttr
... 1
>>> Example.classAttr
... 1
>>> Example.exampleFunc
<function Example.exampleFunc at 0x7fa20525f280>
The instance attribute on the other hand cannot be accessed from the class variable because it is defined when the instance is created.
>>> Example.instanceAttr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Example' has no attribute 'instanceAttr'
>>> ins = Example(2)
>>> ins.instanceAttr
2
How do you write a context manager in Python?
The context manager in Python allows you to automatically set up resources, and then release them when done.
Context managers are used alongside the with
statement. Understanding the inner workings of a context manager will allow you to better comprehend why you get the AttributeError: __enter__ error message.
The most common example a context manager is accessing a file using the with
statement:
>>> with open("test.txt") as f:
... print(f.read())
...
Test file
>>>
Here, you open the file, read it, and then the close file.
All of this happens automatically.
Without the context manager, you would have to do the same task like so:
>>> f = open("test.txt")
>>> print(f.read())
Test file
>>> f.close()
>>>
In other words, you’d need separate lines of code to open, read, and close the file.
Under the hood, a context manager is a class that uses the __enter__ and __exit__ special methods to define how resources are set up and released, respectively. Let’s look at how you can create a context manager with a class and then use it alongside the with
statement:
>>> class ContextManager:
... def __init__(self):
... print("initialized")
... def __enter__(self):
... return "entered!"
... def __exit__(self, exc_type, exc_value, traceback):
... print("exited!")
...
Here, you create the class ContextManager, with the __init__, __enter__ and __exit__ methods. The __enter__ method doesn’t need any arguments and returns the string «entered!», but the __exit__ method requires the three arguments shown. Now, let’s see how the context manager is used alongside a with
statement:
>>> with ContextManager() as cm:
... print("cm:", cm)
... print("processing 1...")
... print("processing 2...")
...
initialized
cm: entered!
processing 1...
processing 2...
exited!
>>>
The output sheds light on the sequence in which each method of the class is executed. First, the __init__ is run, followed by the __enter__ method at the beginning of the with
statement. The output returned from the __enter__ statement is stored in the variable cm
. Next, the code inside the with block is executed. Finally, the __exit__ method is run.
To summarize, the __enter__ method runs some code before the with
statement, and __exit__ method runs code after.
What is attributeerror __enter__?
A Python error object (or exception) in is a problem in the code that causes the program to not work as intended and terminate.
In Python, errors are also known as exceptions.
The AttributeError exception is raised when you try to access an attribute of an object that does not exist.
As you learned in the previous sections, the __enter__ and __exit__ methods are essential for creating a Context Manager, and these methods are also considered to be attributes. So, the AttributeError: __enter__ is raised when using a with
statement with a class that does not have the __enter__ method.
You can simulate the AttributeError: __enter__ error message by creating a ContextManager without the __enter__ method:
>>> class ContextManager:
... def __init__(self):
... print("initialized")
... def __exit__(self, exc_type, exc_value, traceback):
... print("exited!")
...
>>>
>>> with ContextManager() as cm:
... print("processing...")
...
initialized
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __enter__
>>>
Note, that both __enter__ and __exit__ are required for a context manager, so if you only have __enter__ method you would run into the AttributeError: __exit__. If neither of the methods are present, then you would only run into the AttributeError: __enter__ because the __enter__ method is always executed first.
How do you fix attribute errors in Python?
If you defined the context manager yourself and you run into this error, then you should make sure both the __enter__ and __exit__ methods are defined correctly with no typos in their names.
However, if using well-known libraries such as TensorFlow or SQLAlchemy, it’s very unlikely there are any problems with the context manager under the hood. In this case, you should make sure you properly defined the class in the with
statement. There are two common mistakes that would lead to the AttributeError: __enter__ error message.
The first common mistake is if you made a typo in the name of the class of the context manager and there happens to be another object of that name. For example:
>>> class ontextManager:
... pass
...
>>>
>>> with ontextManager() as cm:
... print("cm:", cm)
... print("processing 1...")
... print("processing 2...")
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __enter__
Notice, that instead of calling ContextManager
we call ontextManager
, and there is no class ontextManager in the namespace. This causes us to get the error. It’s important that ontextManager is a class in the namespace; otherwise, this would lead to a NameError.
The second common mistake is where you did not add the parentheses to the class of the context manager. For example:
>>> with ContextManager as cm:
... print("cm:", cm)
... print("processing 1...")
... print("processing 2...")
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __enter__
Note that if you run into the exception AttributeError: __exit__ there must be a problem under the hood, because the __enter__ must be defined, so the context manager would be partially defined.
Summary
In this article, you learned how to fix the AttributeError: __enter__ error message and understood what attributes, context managers, and errors are in Python.
First, you started by understanding what class and instance attributes are in Python, and recalled that methods are also classified as attributes. Next, you learned exactly what context managers are, how you can use them alongside the with
statement, and how to create them with a class in Python. You followed this by learning what the AttributeError: __enter__ is and why it occurs by simulating its exception. Finally, to bring all this information together you understood why the AttributeError: __enter__ is occurring for you and how you can prevent it in the future.
Next Steps
Running into more errors while working with Python? Check out our tutorials on the return outside function error or the Python SyntaxError.
You can read more about the AttributeError in Python’s official documentation. This is a built-in exception, which means it comes as part of of the Python standard library. Your programs will be able to catch such errors out-of-the-box.
To learn more about the basics of Python, coding, and software development, check out our Coding Essentials Guidebook for Developers, where we cover the essential languages, concepts, and tools that you’ll need to become a professional developer.
Thanks and happy coding! We hope you enjoyed this article. If you have any questions or comments, feel free to reach out to jacob@initialcommit.io.
References
- Context Managers — https://book.pythontips.com/en/latest/context_managers.html
- Python Class Attribute: Class Attribute vs. Instance Attribute — https://dzone.com/articles/python-class-attributes-vs-instance-attributes
- Context Manager in Python — https://www.geeksforgeeks.org/context-manager-in-python/
Final Notes
- the
AttributeError: __enter__
in Python - Other Possible Causes and Fixes of
AttributeError: __enter__
in Python - Conclusion
This error is caused by the fact that enter
is an attribute of a metaclass rather than built-in, which means it is not a valid attribute of an instance of the type. In this article, we will discuss what this error is and how to fix it.
the AttributeError: __enter__
in Python
An AttributeError: __enter__
is a common Python error that indicates that a Python object has failed to instantiate with the expected class. The error usually occurs when a class hasn’t been imported correctly.
Also, it can occur if the user has forgotten to call the parent class in the class definition. This error will happen if the user fails to call the parent class when defining a child class.
How the AttributeError: __enter__
Occurs in Python
AttributeError: __enter__
is one of the most confusing error messages you can see in your Python program. It’s not a very clear error message and has many possible causes.
For instance, you can get it if you’re trying to use an object that doesn’t exist or if you’re trying to call a function that doesn’t exist on an object. It’s incredibly frustrating because the error message doesn’t tell you what object you tried to use or what function you tried to call.
It’s not a very helpful error message. The best way to know what is causing this error message is to use the debugger to track down where the error is happening.
Let’s say you want to use the object visitor
of a class DelfStack
inside a with
statement, then the object visitor
must have __exit__
and __enter__
; otherwise, this will produce an error. The __enter__
will be executed first, and the __exit__
will be executed at the end.
Let’s understand it through an example:
class DelfStack():
def __enter__(self):
print('Keep looking for solutions at DELFSTACK')
return "This is __Enter__, it will be executed first"
def __exit__(self,exc_type, exc_val, exc_tb):
print('This is __Exit__, this will be executed at the end')
visitor = DelfStack()
with visitor as obj:
print(obj)
Output:
Keep looking for solutions at DELFSTACK
This is __Enter__, it will be executed first
This is __Exit__, this will be executed at the end
But if we remove the __enter__
, the program will crash and throw an error.
class DelfStack():
#__enter is missing, this will throw an error
def __exit__(self,exc_type, exc_val, exc_tb):
print('This is __Exit__, this will be executed at the end')
visitor = DelfStack()
with visitor as obj:
print(obj)
Output:
----> 7 with visitor as obj:
8 print(obj)
AttributeError: __enter__
As you can see, the above program has thrown the error AttributeError: __enter__
because we are using the object with the with
statement, which demands the __enter__
and __exit__
. In this case, __enter__
is missing, which causes the AttributeError
.
Other Possible Causes and Fixes of AttributeError: __enter__
in Python
The AttributeError: __enter__
is usually caused by a Syntax Error in your Python code. It tells you that the Python interpreter has encountered a Syntax Error while trying to execute a Python statement.
The AttributeError: __enter__
can be due to any of the following reasons:
Compilation Error
In Python, an AttributeError
is a NameError
. When you encounter an AttributeError
, you’re trying to access an attribute on an object (through dot notation) that doesn’t have that attribute attached.
This is different from a TypeError
, which means you’re trying to call a function with the wrong type of arguments.
Syntax Error
The AttributeError: __enter__
error may occur when the programmer does not call the __enter__
method in a class. This gives an error because the program thinks the programmer is trying to call the method __enter__
, which is used in Python to call a class.
The __enter__
method is called when trying to enter a class. For example, if you want to enter a class named C
, you would type __enter__()
in C
.
However, Python thinks you are trying to call the __enter__
method. So, it returns the error AttributeError: __enter__
.
Runtime Error
The Runtime Error of AttributeError: __enter__
is one of the most common errors found while working with Python. This error usually occurs due to the failure of the exec
statement.
The AttributeError
occurs when a variable is not used correctly. This error is mainly generated if we have not used the variable after its declaration.
Import Error
AttributeError: __enter__
can’t set an attribute. In Python, you can use the import
statement’s simple form to define a module’s location; this will load the module into the interpreter.
You can then use the object in that module. Sometimes the error may be due to the Import Error.
Conclusion
AttributeError: __enter__
is a very annoying error that has bothered many users. If you run into this error, you can do a few things to resolve the issue.
First, you can try to import the package into the file you are trying to run. If you are running a Jupyter notebook, you can re-import the package you are having trouble with by using the drop-down menu next to the cell you are trying to run.
If you are getting an AttributeError: __enter__
when running a Python file, you may have forgotten to add the __enter__
method into your class.