Repository: pydicom/pydicom

Issue:
AttributeError on deep copy of FileDataset with empty filename
The following code yields `AttributeError:` 'FileDataset' object has no attribute 'filename'`

```
def test_1():
    import pydicom
    from copy import deepcopy

    file_meta = pydicom.dataset.FileMetaDataset()
    ds = pydicom.FileDataset(filename_or_obj='', dataset={}, file_meta=file_meta, preamble=b'\0' * 128)

    ds2 = deepcopy(ds)
```

Note: use a space as in: `filename_or_obj=' '` does work fine


**Expected behavior**
I would expect empty string for filename_or_obj would just work.

**Steps To Reproduce**


**Your environment**

```
module       | version
------       | -------
platform     | Linux-5.15.13-arch1-1-x86_64-with-glibc2.2.5
Python       | 3.8.12 (default, Oct 26 2021, 08:22:32)  [GCC 11.1.0]
pydicom      | 2.2.2
gdcm         | _module not found_
jpeg_ls      | _module not found_
numpy        | 1.21.5
PIL          | 8.4.0
pylibjpeg    | 1.3.0
openjpeg     | 1.1.1
libjpeg      | 1.2.0
```



Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) Report
> Merging [#1573](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) (6e69379) into [master](https://codecov.io/gh/pydicom/pydicom/commit/d88814fb7da724d1bd207cd9c0ef5415558f5c4f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) (d88814f) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pydicom/pydicom/pull/1573/graphs/tree.svg?width=650&height=150&src=pr&token=YciLV15Lwr&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)

```diff
@@           Coverage Diff           @@
##           master    #1573   +/-   ##
=======================================
  Coverage   97.52%   97.52%           
=======================================
  Files          66       66           
  Lines       10390    10391    +1     
=======================================
+ Hits        10133    10134    +1     
  Misses        257      257           
```


| [Impacted Files](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) | Coverage Δ | |
|---|---|---|
| [pydicom/dataset.py](https://codecov.io/gh/pydicom/pydicom/pull/1573/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9kYXRhc2V0LnB5) | `99.06% <100.00%> (+<0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom). Last update [d88814f...6e69379](https://codecov.io/gh/pydicom/pydicom/pull/1573?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).


Patch:
diff --git a/doc/release_notes/v2.3.0.rst b/doc/release_notes/v2.3.0.rst
index 7f0939097..7bb4229ad 100644
--- a/doc/release_notes/v2.3.0.rst
+++ b/doc/release_notes/v2.3.0.rst
@@ -23,8 +23,9 @@ Enhancements
 
 Fixes
 -----
-
 * Fixed odd-length **OB** values not being padded during write (:issue:`1511`)
 * Fixed Hologic private dictionary entry (0019xx43)
 * Fixed :meth:`~pydicom.dataset.Dataset.compress` not setting the correct
   encoding for the rest of the dataset (:issue:`1565`)
+* Fixed `AttributeError` on deep copy of :class:`~pydicom.dataset.FileDataset`
+  (:issue:`1571`)
diff --git a/pydicom/dataelem.py b/pydicom/dataelem.py
index 66dce4a61..2359df1a6 100644
--- a/pydicom/dataelem.py
+++ b/pydicom/dataelem.py
@@ -11,7 +11,7 @@ import base64
 import json
 from typing import (
     Optional, Any, Tuple, Callable, Union, TYPE_CHECKING, Dict, Type,
-    List, NamedTuple, MutableSequence, cast
+    List, NamedTuple, MutableSequence
 )
 import warnings
 
diff --git a/pydicom/dataset.py b/pydicom/dataset.py
index 73fe20ce9..033f333a7 100644
--- a/pydicom/dataset.py
+++ b/pydicom/dataset.py
@@ -33,6 +33,8 @@ from typing import (
 import warnings
 import weakref
 
+from pydicom.filebase import DicomFileLike
+
 try:
     import numpy
 except ImportError:
@@ -48,7 +50,7 @@ from pydicom.datadict import (
 )
 from pydicom.dataelem import DataElement, DataElement_from_raw, RawDataElement
 from pydicom.encaps import encapsulate, encapsulate_extended
-from pydicom.fileutil import path_from_pathlike
+from pydicom.fileutil import path_from_pathlike, PathType
 from pydicom.pixel_data_handlers.util import (
     convert_color_space, reshape_pixel_array, get_image_pixel_ids
 )
@@ -2616,7 +2618,7 @@ class FileDataset(Dataset):
 
     def __init__(
         self,
-        filename_or_obj: Union[str, os.PathLike, BinaryIO],
+        filename_or_obj: Union[PathType, BinaryIO, DicomFileLike],
         dataset: _DatasetType,
         preamble: Optional[bytes] = None,
         file_meta: Optional["FileMetaDataset"] = None,
@@ -2657,8 +2659,8 @@ class FileDataset(Dataset):
 
         filename: Optional[str] = None
         filename_or_obj = path_from_pathlike(filename_or_obj)
-        self.fileobj_type: Any
-        self.filename: Union[str, BinaryIO]
+        self.fileobj_type: Any = None
+        self.filename: Union[PathType, BinaryIO] = ""
 
         if isinstance(filename_or_obj, str):
             filename = filename_or_obj
diff --git a/source/generate_cids/generate_concept_dicts.py b/source/generate_cids/generate_concept_dicts.py
index 5e4678df5..43ca7b9d1 100755
--- a/source/generate_cids/generate_concept_dicts.py
+++ b/source/generate_cids/generate_concept_dicts.py
@@ -141,7 +141,6 @@ def download_fhir_value_sets(local_dir):
     ftp_path = 'medical/dicom/resources/valuesets/fhir/json'
     logger.info('list files in directory "{}"'.format(ftp_path))
     fhir_value_set_files = ftp.nlst(ftp_path)
-    ftp_url = 'ftp://{host}/{path}'.format(host=ftp_host, path=ftp_path)
 
     try:
         for ftp_filepath in fhir_value_set_files:


Test patch:
diff --git a/pydicom/tests/test_dataset.py b/pydicom/tests/test_dataset.py
index 81e15d08c..5f7b4884a 100644
--- a/pydicom/tests/test_dataset.py
+++ b/pydicom/tests/test_dataset.py
@@ -1925,6 +1925,15 @@ class TestFileDataset:
         ds.preamble = None
         assert ds == ds2
 
+    def test_deepcopy_without_filename(self):
+        """Regression test for #1571."""
+        file_meta = FileMetaDataset()
+        ds = FileDataset(filename_or_obj="", dataset={}, file_meta=file_meta,
+                         preamble=b"\0" * 128)
+
+        ds2 = copy.deepcopy(ds)
+        assert ds2.filename == ""
+
 
 class TestDatasetOverlayArray:
     """Tests for Dataset.overlay_array()."""